【问题标题】:Is it possible to specify more than one type hint for a parameter? [duplicate]是否可以为参数指定多个类型提示? [复制]
【发布时间】:2011-04-19 21:34:47
【问题描述】:

有没有办法为一个方法添加多个类型提示?例如,foo(param) 必须接收字符串 OR bar OR baz 的实例。

【问题讨论】:

标签: php type-hinting


【解决方案1】:

这是无法强制执行的(方法内部除外)。您只能提供单一类型提示,并且只能提供给对象/接口和数组(自 PHP 5.1 起)。

您可以/应该在您的方法中记录它,即:

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

【讨论】:

    【解决方案2】:

    这是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');
    

    【讨论】:

    • 很酷!也有 SPL 类型(实验性):pl.php.net/manual/en/book.spl-types.php
    • @joao:SPLTypes 不能在 5.3 上工作(它们使用已弃用的 c 调用)。加上最后一次更新是在 2008 年,所以可以肯定地说它不是最新的......
    【解决方案3】:

    在撰写本文时,尚不支持多种显式类型。您必须依赖文档和 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 类型,正是这样。

    【讨论】:

    • 您的提案已被拒绝。 PHP8 中是否有这方面的未来计划?
    • 我不知道。我认为值得追求,但我个人将致力于其他功能。
    【解决方案4】:

    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 错误(就像类型提示失败时一样)。

    【讨论】:

    • 我建议发送InvalidArgumentException,这样您至少可以尝试从错误中恢复...
    • @ircmaxell 我只是在演示 OP 如何可以复制类型提示的工作方式。
    • 我并不是说不要trigger_error。这一切都取决于您的风格(使用trigger_error 并没有错)。我更喜欢例外,所以我使用InvalidArgumentException。如果您的目标是模仿类型提示,那么一定会触发致命错误...
    • @ircmaxell 同意;我个人也不会为此使用trigger_error :)
    • 更新:由于 PHP 7 字符串(以及 bool、int、float)是有效的类型提示。
    【解决方案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{}
    

    【讨论】:

    • 很酷,但是 null 是什么?通常的做法是返回一些东西或 null
    猜你喜欢
    • 1970-01-01
    • 2018-07-20
    • 1970-01-01
    • 2018-01-28
    • 2011-05-23
    • 1970-01-01
    • 2011-11-12
    • 1970-01-01
    • 2021-06-15
    相关资源
    最近更新 更多