处理PHP7返回类型的正确方法
我正忙于创建一个应用程序,我想使用PHP7返回类型。现在我在php.net上读到,定义返回类型时,不允许返回处理PHP7返回类型的正确方法,php,oop,php-7,Php,Oop,Php 7,我正忙于创建一个应用程序,我想使用PHP7返回类型。现在我在php.net上读到,定义返回类型时,不允许返回null,这是一个设计决策 正确的处理方法是什么 一个选项是try…catch块: public function getMyObject() : MyObject { return null; } try { getMyObject(); } catch(Exception $e) { //Catch the exception } 我对此感觉不太好,因为
null
,这是一个设计决策
正确的处理方法是什么
一个选项是try…catch块:
public function getMyObject() : MyObject
{
return null;
}
try
{
getMyObject();
}
catch(Exception $e)
{
//Catch the exception
}
我对此感觉不太好,因为我的代码将是一个巨大的try…catch块,因为我需要为每个返回对象的方法编写一个try…catch块
这是一个很好的解决方案,但我不喜欢为应用程序中的每个对象创建NullObject
。
有正确的方法吗
我对此感觉不太好,因为我的代码将是一个巨大的try/catch块,因为我需要为每个返回对象的方法编写一个try/catch块
另一种方法(使用代码)是始终检查null
的返回值,以避免将null
用作对象时出错
使用异常更具表现力,使bug尽早可见,这是一件好事。因此,要么确保您的方法始终返回一个对象,要么在无法履行其契约时抛出异常。否则返回类型没有实际值。如果您的代码希望返回类的实例,在本例中是
MyObject,但它没有,那么这确实是一个异常,应该这样处理
但是,您应该自己抛出这个异常
public function getMyObject() : MyObject
{
throw new MyCustomException("Cannot get my object");
}
然后,您可以捕获该特定异常并相应地进行处理。这在当前是不可能的,尽管如前所述,RFC可能会解决未来版本的问题
到目前为止,您的选择包括:
1.从方法签名中删除返回类型:
public function getMyObject()
{
return null;
}
2.抛出并捕获异常(根据@NiettheDarkAbsol的回答):
3.重构为两种方法:
private $myObject;
//TODO think of a better method name
public function canGetMyObject() : bool
{
$this->myObject = new myObject();
return true;
}
public function getMyObject() : MyObject
{
if(!$this->myObject){
throw new MyCustomException("Cannot get my object");
}
return $this->myObject;
}
呼叫代码:
if($cls->canGetMyObject()){
$myObject = $cls->getMyObject();
}
$myObject = null;
if($cls->tryGetMyObject($myObject)){
$myObject->someMethod(); //$myObject is an instance of MyObject class
}
4.使用布尔返回类型和out参数:
public function tryGetMyObject(&$out) : bool
{
$out = new myObject();
return true;
}
呼叫代码:
if($cls->canGetMyObject()){
$myObject = $cls->getMyObject();
}
$myObject = null;
if($cls->tryGetMyObject($myObject)){
$myObject->someMethod(); //$myObject is an instance of MyObject class
}
第三个和第四个选项只有在预期返回为空且频繁的情况下才真正值得考虑,例如异常的开销是一个因素。
您可能会发现这实际上并不经常适用,例外情况是前进的方向您可以使用选项
数据类型
它是一种将Something
或Nothing
作为包装值的类型
您可以在PHP中找到更详细的描述和一个开放式实现
PS请不要对这种逻辑使用异常、out参数或其他方法,这是一个错误的工具。我也会要求这样做。我不认为这有什么意义
如果我有以下按名称查找用户的示例代码:
<?php
class User
{
protected $name;
/**
* User constructor.
*
* @param $name
*/
public function __construct(string $name)
{
$this->name = $name;
}
/**
* @return mixed
*/
public function getName() : string
{
return $this->name;
}
}
function findUserByName(string $name, array $users) : User {
foreach ($users as $user) {
if ($user->getName() == $name) {
return $user;
}
}
return null;
}
$users = [
new User('John'), new User('Daniel')
];
$user = findUserByName('John', $users);
echo $user->getName()."\n";
$user2 = findUserByName('Micheal', $users);
从PHP7.1开始,您可以使用可为空的返回类型:
public function getMyObject(): ?MyObject {
return null;
}
返回false
?简单的数据类型,但仍然清楚它未能初始化对象。PHP7.1接受了void返回类型。所以它将在将来出现。明智的解决方案是确保getMyObject
返回实际的对象。看起来您的对象可能处于次优的无效状态。但是如果你对你的代码一无所知,就很难猜测了。void
返回类型与这种情况无关。我真的不明白这个问题,但不管它是什么:你永远不应该随便捕获错误
异常。除非您有一些非常特殊的情况,否则您的应用程序应该只在一个地方捕获这些异常:顶级异常处理程序。我认为您在这里寻找的是简单地去掉类型注释。这仍然是允许的。如果您的返回值是“object或null”,那么这就是您应该做的(直到我们引入可为null的类型为止)。也许这是一种避免try/catch块的习惯,但我认为现在是接受这种行为并利用其好处的好时机。如果Null对象没有意义(通常是这样),那么添加第二个方法hasMyObject()
是有意义的,您可以在实际获取它之前进行检查。这是最明确的方法。从不同的答案中,我觉得最好的方法是抛出自定义异常。我会试试看,希望这些开销是值得的!是的,这可能是真的,上面的其他选项只适用于特定情况,有些人会认为例外是最好的解决方案。注意:我添加了第四种方法,您可能更喜欢第三种方法,即有任何方法可以拥有特定对象的数组:类似于公共函数getMyObject():数组[MyObject]
?这看起来像Haskell,必须是。