我正忙着创建一个应用程序,我想使用PHP 7返回类型。现在我在php.net上读到这是一个设计决定,当定义了返回类型时,不允许返回null
。
处理这个问题的正确方法是什么?
一个选项是try ... catch块:
public function getMyObject() : MyObject
{
return null;
}
try
{
getMyObject();
}
catch(Exception $e)
{
//Catch the exception
}
我对此没有很好的感觉,因为我的代码将是一个巨大的尝试... catch块因为我需要为每个返回对象的方法编写一个try ... catch块。
Null Object Pattern对此很好,但我不喜欢为我的应用程序中的每个对象创建NullObject
。
有没有正确的方法来做到这一点?
答案 0 :(得分:27)
如果你的代码希望返回一个类的实例,在这种情况下是MyObject
,但它没有,那么这确实是一个例外,应该这样处理。
但是,您应该自己抛出此异常。
public function getMyObject() : MyObject
{
throw new MyCustomException("Cannot get my object");
}
然后您可以捕获该特定异常并相应地继续。
答案 1 :(得分:6)
我对此没有很好的感觉,因为我的代码将是一个巨大的try / catch块,因为我需要为每个返回对象的方法编写一个try / catch块。
替代方法(使用您的代码)将始终检查null
的返回值,以避免使用null
作为对象时出错。
使用异常更具表现力,并且可以及早发现错误,这是一件好事。因此,要么确保您的方法始终返回一个对象,要么在它无法履行合同时抛出异常。否则返回类型没有实际值。
答案 2 :(得分:6)
您可以使用Option
数据类型。
这是一种以Something
或Nothing
作为包装值的类型。
您可以在PHP here中找到更详细的说明here和其中一个开放式实现
PS请不要为这种逻辑使用异常,输出参数或其他方法,这对于这项工作来说是错误的工具。
答案 3 :(得分:3)
目前这是不可能的,尽管如前所述,有些RFC可能会解决未来版本的问题。
截至目前,您的选择是:
1.从方法签名中删除返回类型:
public function getMyObject()
{
return null;
}
2.Throw并捕捉异常(根据@ NiettheDarkAbsol的回答):
public function getMyObject() : MyObject
{
throw new MyCustomException("Cannot get my object");
}
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();
}
4.使用bool返回类型和out参数:
public function tryGetMyObject(&$out) : bool
{
$out = new myObject();
return true;
}
致电代码:
$myObject = null;
if($cls->tryGetMyObject($myObject)){
$myObject->someMethod(); //$myObject is an instance of MyObject class
}
第3和第4个选项在预期空返回和frequant的情况下才真正值得考虑,因此异常的开销是一个因素。 可能你会发现这并不经常适用所有这些,例外是前进的方式
答案 4 :(得分:1)
从PHP7.1开始,您可以使用可空的返回类型:
public function getMyObject(): ?MyObject {
return null;
}
答案 5 :(得分:0)
我打算要求同样的。我没有注意到这一点。
如果我有以下示例代码来按名称查找用户:
<?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);
我想告诉Php我可以获得User或null。现在我需要将它总是包装在try catch块中,在这种情况下,我没有太多意义来声明返回类型。另一方面,如果我的findUserByName
函数很复杂,我可能会意外返回例如用户名而不是完整的用户对象,因此我希望定义返回类型。
我认为更合理的是为函数定义多个返回类型。有时你创建返回一个对象或对象数组的函数,定义很好,这个函数应该返回例如User
或用户数组:User[]
。
在OP情况下(也是我的)我们可以将返回类型声明为User, null
,它可以解决问题。