2010-10-01 19 views
14

C'è un modo per aggiungere più di un tipo a un metodo? Ad esempio, foo (param) deve ricevere un'istanza di string OR bar O baz.È possibile specificare più di un suggerimento per un parametro?

+0

L'hint di tipo non supporta gli scalari di stringa; solo sottolineando questo. – Qix

+0

@Qix Dovremmo ora ricordare che [PHP supporta l'hint di tipo scalare come da PHP 7.0.0] (http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration). – faintsignal

risposta

6

Type hinting permette solo per un suggerimento per parametro (e anche, il suggerimento deve essere array o un nome di classe, non si può accennare string), ma è possibile farlo controllando il tipo di parametro all'interno della vostra funzione , utilizzando get_class:

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

si potrebbe anche usare trigger_error avere fallire con un errore PHP (come sarebbe se un tipo di suggerimento fallito) se si voleva.

+3

Suggerirei di lanciare un 'InvalidArgumentException', in modo che tu possa almeno tentare di recuperare dall'errore ... – ircmaxell

+1

@ircmaxell Stavo solo dimostrando come l'OP * potrebbe * replicare come funzionano i tipi di suggerimenti. –

+0

Non sto dicendo di non usare 'trigger_error'. Tutto dipende dal tuo stile (e non c'è niente di sbagliato nell'uso di 'trigger_error'). Preferisco le eccezioni, quindi uso 'InvalidArgumentException'. Se il tuo obiettivo è quello di imitare i suggerimenti di tipo, quindi innescare tutti un errore fatale ... – ircmaxell

22

Ciò non è possibile applicare (tranne all'interno del metodo). È possibile fornire solo un suggerimento di tipo singolo e solo per oggetti/interfacce e matrici (da PHP 5.1).

Si può/deve tuttavia documentarlo nel metodo, cioè:

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

+1 per documentazione – Hannes

10

Questo è uno uso di interfaces. Se si vuole essere sicuri che l'oggetto ha un metodo ->foobar($baz), ci si potrebbe aspettare un'interfaccia:

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

Poi, quando si chiama, questo non funziona:

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

Questi non:

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

Piuttosto interessante! Ci sono anche i tipi SPL (sperimentale): http://pl.php.net/manual/en/book.spl-types.php – joao

+0

allo stesso modo in cui l'ho fatto. – ITroubs

+0

@joao: SPLTypes non funziona su 5.3 (Usano chiamate c deprecate). Inoltre l'ultimo aggiornamento è stato nel 2008, quindi è abbastanza sicuro dire che non è aggiornato ... – ircmaxell

5

Domanda fantastica. Si applica sia alla documentazione IDE che a PHP 5 Type Hinting. Devi ricordare che in OO polymorphism è tuo amico.

Se crei una classe base ed estendali, il tuo suggerimento tipo sarà la classe base ... tutta la classe estesa funzionerà. Vedi l'esempio qui sotto.

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

Al momento della stesura di questo documento non è supportato più tipi espliciti. Devi fare affidamento sulla documentazione e sul sistema di tipo dinamico di PHP.

Tuttavia, ho una proposta per lo più incompleta per union types. Ha come target 7.NEXT (al momento in cui scrivo questo è 7.1) o 8 (a seconda di quale viene prima).

Ecco un semplice esempio di qualcosa che penso sarebbe molto prezioso: array | Traversable:

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

Purtroppo la RFC non ha superato; tuttavia per il tipo specifico array|Traversable c'è ora un tipo iterable che è esattamente quello.

Problemi correlati