2010-10-01 352 views
14

有沒有辦法給方法添加多個類型提示?例如,foo(param)必須接收字符串OR bar或baz的實例。是否可以爲參數指定多個類型提示?

+0

類型提示不支持字符串標量;只是指出了。 – Qix 2014-10-13 21:35:16

+0

@Qix現在我們應該提到[PHP支持自PHP 7.0.0起的標量類型暗示](http://php.net/manual/en/functions.arguments.php#functions.arguments.type- declare)。 – faintsignal 2017-08-28 22:02:03

回答

6

Type hinting只允許每個參數的一個提示(並且也提示必須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錯誤(像它會如果一個類型提示失敗),如果你想要的。

+3

我建議拋出一個'InvalidArgumentException',這樣你至少可以嘗試從錯誤中恢復...... – ircmaxell 2010-10-01 14:48:42

+1

@ircmaxell我只是演示了OP *如何*複製類型提示的工作方式。 – 2010-10-01 14:54:41

+0

我不是說不要'trigger_error'。這一切都取決於你的風格(並且使用'trigger_error'沒有什麼錯誤)。我更喜歡異常,所以我使用'InvalidArgumentException'。如果你的目標是模仿類型提示,那麼通過一切手段觸發致命錯誤... – ircmaxell 2010-10-01 15:00:53

22

這是不可能執行(除了在方法內)。你只能提供一個單一的類型提示,並且只能提供對象/接口和數組(從PHP5.1開始)。

可以/但是應該在你的方法將其記錄下來,即:

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

+1文檔 – Hannes 2010-10-01 14:44:26

10

這是一個利用interfaces。如果你想確保對象具有->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'); 
+0

很酷!也有SPL類型(實驗):http://pl.php.net/manual/en/book.spl-types.php – joao 2010-10-01 14:55:10

+0

我也是這樣做的。 – ITroubs 2010-10-01 16:46:06

+0

@joao:SPLTypes在5.3上不起作用(它們使用不推薦的c調用)。另外最後一次更新是在2008年,所以說它不是最新的是很安全的... – ircmaxell 2010-10-01 17:45:40

5

奇妙的問題。它適用於IDE文檔和PHP 5 Type Hinting。 你必須記住,在OO polymorphism是你的朋友。

如果你創建一個基類並擴展它們,你的類型提示將是基類......所有的擴展類都可以工作。見下面的例子。

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

在寫這篇文章時,不支持多顯式類型。你必須依賴文檔和PHP的動態類型系統。

但是,我確實有一個主要不完整的建議union types。它的目標是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類型,正是這種類型。

相關問題