2010-10-01 12 views
14

Czy istnieje sposób dodania więcej niż jednego typu podpowiedzi do metody? Na przykład, foo (param) musi otrzymać instancję ciągu LUB paska OR baz.Czy można określić więcej niż jedną wskazówkę dotyczącą parametru?

+0

Podpowiedź typów nie obsługuje skalarów ciągów; tylko to wskazuję. – Qix

+0

@Qix Powinniśmy teraz wspomnieć, że [PHP obsługuje podpowiedź typu skalarnego od PHP 7.0.0] (http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration). – faintsignal

Odpowiedz

6

Type hinting pozwala tylko na jedną wskazówkę na parametr (a także, wskazówka musi być array lub nazwę klasy, nie można schować string), ale można to zrobić poprzez sprawdzenie typ param wewnątrz swojej funkcji korzystając get_class:

function foo($param) 
{ 
    if (!(is_string($param) || in_array(get_class($param), array("Bar", "Baz"))) 
    { 
    // invalid type for $param! 
    } 
} 

można nawet użyć trigger_error mieć ona niepowodzeniem z błędem PHP (jak byłoby gdyby wskazówkę typu nie powiodło się), jeśli chcieli.

+3

Proponuję rzucić 'InvalidArgumentException', dzięki czemu można przynajmniej spróbować odzyskać od błędu ... – ircmaxell

+1

@ircmaxell Właśnie pokazałem, w jaki sposób OP * może * powielić sposób działania wskazówek dotyczących typów. –

+0

Nie mówię, że nie "trigger_error". Wszystko zależy od twojego stylu (i nie ma nic złego w używaniu 'trigger_error'). Preferuję wyjątki, więc używam 'InvalidArgumentException'. Jeśli twoim celem jest naśladowanie podpowiedzi typu, to wszelkimi sposobami wywołaj fatalny błąd ... – ircmaxell

22

Nie można tego wykonać (z wyjątkiem metody). Możesz podać tylko jedną wskazówkę typu i tylko dla obiektów/interfejsów i tablic (od PHP 5.1).

można/należy jednak udokumentować go w sposób, tj:

/** 
* @param string|Bar|Baz $param1 
*/ 
function foo($param1); 
+3

+1 dla dokumentacji – Hannes

10

To jedno użycie interfaces. Jeśli chcesz mieć pewność, że obiekt ma metodę ->foobar($baz), można spodziewać się interfejs:

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'); 
} 

Potem, gdy dzwoni, to będzie działać:

doSomething(new Foo()); 
doSomething(new Bar()); 

te nie będą:

doSomething(new StdClass()); 
doSomething('testing'); 
+0

Całkiem fajnie! Istnieją również typy SPL (eksperymentalne): http://pl.php.net/manual/en/book.spl-types.php – joao

+0

w ten sam sposób, w jaki to zrobiłem. – ITroubs

+0

@joao: SPLTypes nie będzie działać w wersji 5.3 (używają przestarzałych wywołań c). Plus ostatnia aktualizacja była w 2008 r., Więc całkiem bezpiecznie jest powiedzieć, że nie jest aktualna ... – ircmaxell

5

Fantastyczne pytanie. Dotyczy to zarówno dokumentacji IDE, jak i PHP 5 Type Hinting. Musisz pamiętać, że w OO polymorphism jest twoim przyjacielem.

Jeśli utworzysz klasę bazową i przedłużysz je, twoja podpowiedź będzie klasą podstawową ... wszystkie klasy rozszerzone będą działały. Zobacz przykład poniżej.

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

W czasie pisania tego tekstu nie ma obsługi wielu typów jawnych. Musisz polegać na dokumentacji i dynamicznym systemie PHP.

Mam jednak najczęściej niekompletną propozycję dla union types. Jest ukierunkowany na 7.NEXT (w momencie pisania tego jest 7.1) lub 8 (w zależności od tego, co nastąpi wcześniej).

Oto prosty przykład czegoś, co myślę, że byłaby bardzo cenna: array | Traversable:

function map(callable $fn, array|Traversable $input) { 
    foreach ($input as $key => $value) { 
     yield $key => $fn($value); 
    } 
} 

Niestety RFC nie przechodzą; jednak dla określonego typu array|Traversable istnieje teraz typ: iterable.

Powiązane problemy