2010-10-01 14 views
14

¿Hay alguna manera de agregar más de un tipo de sugerencia a un método? Por ejemplo, foo (param) debe recibir una instancia de cadena OR bar O baz.¿Es posible especificar más de una sugerencia de tipo para un parámetro?

+0

La sugerencia de tipo no admite escalas de cadena; solo señalando eso. – Qix

+0

@Qix Ahora deberíamos mencionar que [PHP admite insinuaciones de tipo escalar a partir de PHP 7.0.0] (http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration). – faintsignal

Respuesta

6

Type hinting sólo permite un atisbo por parámetro (y también, la insinuación es necesario que haya array o un nombre de clase, no se puede hacer alusión string), pero se puede hacer esto mediante la comprobación del tipo del parámetro dentro de su función , utilizando get_class:

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

incluso podría utilizar trigger_error tener que fallar con un error de PHP (como sería si un tipo de pista no) si querías.

+3

Sugeriría arrojar una 'InvalidArgumentException', para que al menos pueda intentar recuperarse del error ... – ircmaxell

+1

@ircmaxell Solo estaba demostrando cómo el OP * podría * replicar cómo funcionan las sugerencias de tipo. –

+0

No estoy diciendo que no 'trigger_error'. Todo depende de tu estilo (y no hay nada de malo con el uso de 'trigger_error'). Prefiero las excepciones, entonces uso 'InvalidArgumentException'. Si su objetivo es imitar sugerencias de tipo, entonces, por supuesto, desencadenar un error fatal ... – ircmaxell

22

Eso no es posible hacer cumplir (excepto dentro del método). Solo puede proporcionar una sugerencia de tipo único, y solo a objetos/interfaces y matrices (desde PHP 5.1).

Puede/sin embargo debe documentar en su método, es decir:

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

+1 para documentación – Hannes

10

Este es un uso de interfaces. Si usted quiere estar seguro de que el objeto tiene un método ->foobar($baz), se puede esperar una interfaz:

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

Entonces, al llamar, éstos funcionarán:

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

Estos no:

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

¡Bastante bien! También hay tipos SPL (experimentales): http://pl.php.net/manual/en/book.spl-types.php – joao

+0

de la misma manera que lo había hecho. – ITroubs

+0

@joao: SPLTypes no funcionará en 5.3 (usan llamadas obsoletas c). Además, la última actualización fue en 2008, por lo que es bastante seguro decir que no es actual ... – ircmaxell

5

Pregunta fantástica. Se aplica tanto a la documentación IDE como a PHP 5 Type Hinting. Tienes que recordar que en OO polymorphism es tu amigo.

Si crea una clase base y la amplía, su sugerencia de tipo será la clase base ... toda la clase extendida funcionará. Vea el ejemplo a continuación.

// 
$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

En este momento no hay soporte para múltiples tipos explícitos. Debe confiar en la documentación y en el sistema de tipo dinámico de PHP.

Sin embargo, tengo una propuesta casi incompleta para union types. Tiene como objetivo 7.NEXT (en el momento de escribir esto, esto es 7.1) u 8 (lo que ocurra primero).

Aquí es un simple ejemplo de algo que creo que sería muy valiosa: array | Traversable:

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

Por desgracia, la RFC no pasó; sin embargo, para el tipo específico array|Traversable ahora existe un tipo iterable que es exactamente eso.

Cuestiones relacionadas