Я занят созданием приложения, и я хочу использовать возвращаемые типы PHP 7. Теперь я прочитал на php.net, что было конструктивным решением о том, что ему не разрешено возвращать null
когда определен тип возврата.
Каков правильный способ справиться с этим?
Одним из вариантов является блок try … catch:
public function getMyObject() : MyObject { return null; } try { getMyObject(); } catch(Exception $e) { //Catch the exception }
У меня нет хорошего представления об этом, потому что мой код будет огромной попыткой … catch block, так как мне нужно написать try … catch block для каждого метода, который возвращает объект.
Шаблон нулевого объекта является хорошим решением для этого, но мне не нравится идея создания NullObject
для каждого объекта в моем приложении. Есть ли правильный способ сделать это?
У меня нет хорошего представления об этом, потому что мой код будет огромным блоком try / catch, так как мне нужно написать блок try / catch для каждого метода, который возвращает объект.
Альтернативой (с вашим кодом) было бы всегда проверять возвращаемое значение для null
чтобы не получить ошибки от использования null
в качестве объекта.
Использование исключений более выразительно и делает ошибки видимыми рано, что хорошо. Поэтому либо убедитесь, что ваш метод всегда возвращает объект, либо генерирует исключение, если он не может выполнить свой контракт. В противном случае тип возврата не имеет реального значения.
Если ваш код ожидает возврата экземпляра класса, в данном случае MyObject
, но это не так, то это действительно исключение и должно рассматриваться как таковое.
Однако вы должны выбросить это исключение самостоятельно.
public function getMyObject() : MyObject { throw new MyCustomException("Cannot get my object"); }
Затем вы можете поймать это конкретное исключение и действовать соответствующим образом.
Вы можете использовать тип данных Option
.
Это тип, который имеет что- Something
или Nothing
как завернутое значение.
Вы можете найти более подробное описание здесь и одну из открытых реализаций в PHP здесь
PS, пожалуйста, не используйте исключения, параметры или дополнительные методы для такой логики, это неправильный инструмент для работы.
В настоящее время это невозможно, хотя, как уже упоминалось, есть RFC, которые могут решить проблему для будущих версий.
На данный момент ваши варианты:
1.Заверните тип возврата из вашей сигнатуры метода:
public function getMyObject() { return null; }
2.Throw и поймать исключение (в соответствии с ответом @ NiettheDarkAbsol):
public function getMyObject() : MyObject { throw new MyCustomException("Cannot get my object"); }
3.Refactor для двух методов:
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(); }
-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 }
-$myObject = null; if($cls->tryGetMyObject($myObject)){ $myObject->someMethod(); //$myObject is an instance of MyObject class }
3-й и 4-й варианты действительно заслуживают рассмотрения в тех случаях, когда ожидается нулевой возврат и частота, так что накладные расходы исключений являются фактором. Вероятно, вы обнаружите, что это фактически не применяет все это часто, а исключения – это путь вперед
Я собирался попросить об этом. Я не вижу большого смысла для этого.
Если у меня есть следующий пример кода, чтобы найти пользователя по имени:
<?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, что я могу получить либо Пользователь, либо null. Теперь мне нужно обернуть его всегда в блок catch catch, и я не вижу смысла объявлять тип возвращаемого значения в этом случае. С другой стороны, если моя функция findUserByName
будет сложной, я могу случайно вернуться, например, к имени пользователя вместо полного пользовательского объекта, поэтому я хотел бы иметь тип возвращаемого типа.
Я думаю, что гораздо более разумным было бы определение нескольких типов возврата для функций. Иногда вы создаете функцию, возвращающую один объект или массив объектов, и было бы неплохо определить, эта функция должна возвращать, например, User
или массив пользователей: User[]
.
В случае OP (а также my) мы могли бы объявить возвращаемый тип как User, null
и это решило бы проблему.
Начиная с PHP7.1, вы можете использовать типы возвращаемых значений:
public function getMyObject(): ?MyObject { return null; }