Можно ли указать более одной подсказки типа для параметра? - PullRequest
18 голосов
/ 01 октября 2010

Есть ли способ добавить несколько подсказок типа к методу? Например, foo (param) должен получить экземпляр строки OR bar OR baz.

Ответы [ 5 ]

26 голосов
/ 01 октября 2010

Это невозможно осуществить (кроме как внутри метода). Вы можете предоставить только один тип подсказки и только для объектов / интерфейсов и массивов (начиная с PHP 5.1).

Вы можете / должны, однако, документировать это в своем методе, то есть:

/**
 * @param string|Bar|Baz $param1
 */
function foo($param1);
16 голосов
/ 01 октября 2010

Это одно использование интерфейсов . Если вы хотите быть уверены, что у объекта есть метод ->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');
11 голосов
/ 12 мая 2015

На момент написания этой статьи не было поддержки нескольких явных типов. Вы должны полагаться на документацию и динамическую систему типов 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, который является именно этим.

6 голосов
/ 01 октября 2010

Тип подсказки допускает только одну подсказку для параметра (а также подсказка должна быть 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 (как это было бы при неудачной подсказке типа), если бы вы хотели.

5 голосов
/ 01 октября 2010

Фантастический вопрос. Это относится как к документации IDE, так и к PHP 5 Type Hinting . Вы должны помнить, что в ОО полиморфизм является вашим другом.

Если вы создадите базовый класс и расширите их, ваша подсказка типа будет базовым классом ... весь расширенный класс будет работать. Смотрите пример ниже.

//
$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{}
...