2010-10-01 151 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类型,正是这种类型。

相关问题