Есть ли способ добавить в метод более одного намека на тип? Например, foo(param) должен получить экземпляр строки ИЛИ bar ИЛИ baz.
Можно ли указать более одной подсказки типа для параметра?
Ответы (5)
Это невозможно применить (кроме как внутри метода). Вы можете указать только один тип подсказки и только для объектов/интерфейсов и массивов (начиная с PHP 5.1).
Однако вы можете/должны документировать это в своем методе, то есть:
/**
* @param string|Bar|Baz $param1
*/
function foo($param1);
Это одно из применений интерфейсов. Если вы хотите быть уверены, что у объекта есть метод ->foobar($baz)
, вы можете ожидать интерфейс:
interface iFooBar {
public function foobar($baz);
}
class Foo implements iFooBar {
public function foobar($baz) { echo $baz; }
}
class Bar implements iFooBar {
public function foobar($baz) { print_r($baz); }
}
function doSomething(iFooBar $foo) {
$foo->foobar('something');
}
Затем при вызове они будут работать:
doSomething(new Foo());
doSomething(new Bar());
Это не будет:
doSomething(new StdClass());
doSomething('testing');
На момент написания этой статьи не было поддержки нескольких явных типов. Вы должны полагаться на документацию и динамическую систему типов PHP.
Однако у меня есть в основном неполное предложение для типов объединений. Он нацелен на 7.NEXT (на момент написания этой статьи это 7.1) или 8 (в зависимости от того, что наступит раньше).
Вот простой пример того, что, как мне кажется, будет очень ценным: array | Traversable
:
function map(callable $fn, array|Traversable $input) {
foreach ($input as $key => $value) {
yield $key => $fn($value);
}
}
К сожалению, RFC не прошел; однако для конкретного типа array|Traversable
теперь есть тип iterable
, который является именно таким.
Подсказка типа допускает только одну подсказку для каждого параметра (а также подсказку должно быть array
или имя класса, вы не можете указать string
), но вы можете сделать это, проверив тип параметра в вашей функции, используя get_class
:
function foo($param)
{
if (!(is_string($param) || in_array(get_class($param), array("Bar", "Baz")))
{
// invalid type for $param!
}
}
Вы даже можете использовать trigger_error
, чтобы он не работал с ошибкой PHP. (как если бы подсказка типа не сработала), если хотите.
InvalidArgumentException
, чтобы вы могли хотя бы попытаться восстановиться после ошибки...
- person ircmaxell; 01.10.2010
trigger_error
. Все зависит от вашего стиля (и нет ничего плохого в использовании trigger_error
). Я предпочитаю исключения, поэтому использую InvalidArgumentException
. Если ваша цель - имитировать подсказки типа, то во что бы то ни стало вызовите фатальную ошибку...
- person ircmaxell; 01.10.2010
trigger_error
для этого :)
- person Daniel Vandersluis; 01.10.2010
Фантастический вопрос. Это относится как к документации IDE, так и к подсказкам типов PHP 5. Вы должны помнить, что в ОО полиморфизм — ваш друг.
Если вы создадите базовый класс и расширите их, ваша подсказка типа будет базовым классом... все расширенные классы будут работать. См. пример ниже.
//
$test = new DUITest();
// Calls below will work because of polymorphism
echo $test->test(new Molecule()) . '<br/>';
echo $test->test(new Vodka()) . '<br/>';
echo $test->test(new Driver()) . '<br/>';
echo $test->test(new Car()) . '<br/>';
// Will not work because different data type
echo $test->test(new Pig()) . '<br/>';
echo $test->test(new Cop()) . '<br/>';
echo $test->test('test') . '<br/>';
echo $test->test(array()) . '<br/>';
/**
* Class to test
*/
class DUITest {
public function __construct() {
;
}
/**
* Using type-hinting
*
* See below link for more information
* @link http://www.php.net/manual/en/language.oop5.typehinting.php
*
* @param Molecule|Car|Driver|Vodka $obj
*/
public function test(Molecule $obj) {
echo $obj;
}
}
/**
* Base Class
*/
class Molecule {
public function __construct() {}
/**
* Outputs name of class of current object
* @return <type>
*/
public function __toString() {
return get_class($this);
}
}
class Car extends Molecule {}
class Driver extends Molecule {}
class Vodka extends Molecule {}
class Pig {}
class Cop extends Pig{}