【问题标题】:PHP Type Hinting: array supported, object NOT?PHP 类型提示:支持数组,对象不是?
【发布时间】:2010-12-05 14:00:57
【问题描述】:

我是否遗漏了什么,或者 PHP 5.x 中确实不支持泛型对象类型提示?

我觉得很奇怪,提示数组受支持而提示对象不支持,至少不是开箱即用。

我想要这样的东西:

function foo(object $o)

就像我们一样:

function foo(array $o)

可能的使用示例:对象集合类的方法。

解决方法:使用由所有类实现的接口“Object”或从通用类“Object”扩展所有类并编写如下内容:

function foo(Object $o)

嗯,那不可爱。

使用stdClass 作为类型提示不起作用:

可捕获的致命错误:参数 1 传递给 c::add() 必须是一个实例 stdClass 的实例,给定的 b 实例

【问题讨论】:

  • 不要使用具体类型进行类型提示。要么使用接口,要么阅读鸭子类型。
  • 如果我要走没有具体类型的道路,我宁愿使用 is_object()。但这不是本次讨论的重点。
  • 看,PHP 是一种非常不一致的语言,其中的对象不像 Java 那样从单个类继承。一般对象没有类型提示的事实确实是一个疏忽,但我认为你必须通过这一点并为其他奇怪的事情做好准备。
  • 数组提示如何比 is_array() 更好?由于支持数组提示,我希望对象也是如此。
  • @IonuțG.Stan is_array 在每个函数中检查和抛出异常比设置全局异常处理程序更容易吗?你一定是在开玩笑吧。

标签: php oop


【解决方案1】:

由于类型提示应该使客户端代码适应您的 API,您的带有接受接口的解决方案似乎恰到好处。

这样看:yourMethod(array $input) 给了yourMethod() 一个要使用的数组,因此您知道exactly which native functions 适用并且可以被yourMethod() 使用。

如果您指定您的方法,例如:yourSecondMethod(yourInterface $input),您还将知道哪些方法可以应用于$input,因为您知道/可以查找接口yourInterface 附带的一组规则。

在您的情况下,接受任何对象似乎都是错误的,因为您无法知道在输入上使用哪些方法。示例:

function foo(Object $o) {
    return $o->thisMethodMayOrMayNotExist();
}

(不暗示语法有效)

【讨论】:

  • 对象集合类的情况并非如此,它将充当(伪)容器,不会对其子级调用任何方法,也不会使用它们的任何属性/属性。知道一个变量是一个对象也可以在它上面使用很多本机函数,所以我真的不明白你的意思。
  • 使用类型提示如 SplObjectStorage 或 ArrayObject 怎么样?
  • 简单容器对象有\stdClass
【解决方案2】:

不,不能这样做。我没有错过任何东西。

【讨论】:

  • 从 PHP 7.2 开始,您终于可以声明您想要的方式了:function functionName(object $someObjectVariable) 请参阅下一页上名为“有效类型”的表格:(php.net/manual/en/…)
【解决方案3】:

我感觉到你的痛苦,但我也找不到办法。

尽管许多其他发帖人已经说过,想要“对象”类型提示是完全合理的;他们只是没有考虑需要它的场景。

我正在尝试使用反射 API 做一些工作,因此我不在乎将什么类传递给我的函数。我只关心它是一个对象。我不想要一个 int、一个浮点数、一个字符串或一个数组。我想要一个对象。鉴于反射现在是 PHP 的一部分,因此具有对象类型提示绝对是有意义的。

【讨论】:

    【解决方案4】:

    在类型转换对象时不能只说“对象”...您必须定义您期望的对象。

    发件人:http://php.net/manual/en/language.oop5.typehinting.php

    class MyClass
    {
        /**
         * A test function
         *
         * First parameter must be an object of type OtherClass
         */
        public function test(OtherClass $otherclass) {
            echo $otherclass->var;
        }
    
    
        /**
         * Another test function
         *
         * First parameter must be an array
         */
        public function test_array(array $input_array) {
            print_r($input_array);
        }
    }
    
    // Another example class
    class OtherClass {
        public $var = 'Hello World';
    }
    

    【讨论】:

      【解决方案5】:

      执行此操作的最佳方法是创建一个名为Object 的退化接口。退化的接口意味着它没有定义的方法。

      interface Object {
      
         // leave blank
      
      }
      

      然后在你的基类中,你可以实现Object

      class SomeBase implements Object {
      
         // your implementation
      
      }
      

      您现在可以根据需要调用您的函数

      function myFunc (Object $obj);
      
      myFunc($someBase);
      

      如果您传递任何继承自 Object 接口的对象,则此类型提示将通过。如果传入数组、int、字符串等,类型提示会失败。

      【讨论】:

      • 不幸的是,这可能是您在 PHP 中最接近的,但这确实意味着您创建的每个类都必须实现 Object 接口,这确实是很多开销就这么简单。啊啊啊,PHP..
      • OP 已经在问题中将这种策略描述为一种可能的解决方法,这有点糟糕;这不会让您传递实例内置类或第三方库中定义的类。
      【解决方案6】:

      这是另一个需要它的示例...

      我创建了一个类来实现记录锁定。记录是许多不同对象类型之一。锁定类有几个方法需要一个对象(要锁定的对象),但不关心它是什么类型的对象。

      例如

      public static function lockRecord($record, User $user, $timeout=null)
      {
          if(!is_object($record)) throw new \InvalidException("Argument 1 must be an object.");
      
          $lock=new Lock();
          $lock->setRecord($record);
          $lock->setUser($user);
          $lock->setTimeout($timeout);
          $lock->activate();
          return($lock);
      }
      

      您会看到我的解决方案是使用 is_object() 并引发异常,但我宁愿使用类型提示来代替。

      好吧,所以不是世界末日,但我认为这是一种耻辱。

      【讨论】:

        【解决方案7】:

        php 中的对象不是某些 StdClass 或 Object 的子类,就像在其他 OOP 语言中一样。所以没有办法对对象进行类型提示。但我明白你的意思,因为有时你想确保 Object 正在被传递,所以我想唯一的方法是手动提出问题。

        public function yourFunction($object){
            if(is_object($object)){
                //TODO: do something
            }else{
                throw new InvalidArgumentException;
            }
        }
        

        从 php 5.4 开始,还有一个类型提示 callable。 见php手册http://php.net/manual/en/language.types.callable.php

        【讨论】:

          【解决方案8】:

          当您可以提示实际的类名时,您为什么要提示object - 这会更有用。还要记住,你不能暗示intfloatboolstringresource

          【讨论】:

          • 为什么要命中数组?记住所有那些你不能暗示的其他类型......因为没有一个公共基类可以继承所有 PHP 类,所以能够暗示一个对象是有意义的,就像暗示一个数组一样。我的意见,但我怀疑我是独自一人。
          • 仅仅因为你想不出一个对泛型对象进行类型提示的实例,并不意味着永远不存在这种需要。Rikki 的评论就是一个完美的例子。在我看来,你不能为 int、float、bool、string 和 resource 输入提示也是一个疏忽。在很多情况下,我宁愿明确地将参数限制为整数。所以相反,我被困在使用“is_int”无意义的调用。
          【解决方案9】:
          public static function cloneObject($source)
          {
              if ($source === null)
              {
                  return null;
              }
          
              return unserialize(serialize($source));
          }
          

          这是你需要它的地方。

          【讨论】:

          • 为了提高您的回答质量,请说明您的帖子解决问题的方式/原因。
          【解决方案10】:

          PHP 7.2 开始,您终于可以按照自己的方式声明:

          function functionName(object $someObjectVariable)

          请参阅此页面上名为“有效类型”的表格: https://www.php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration

          【讨论】:

            猜你喜欢
            • 2017-09-09
            • 2018-01-04
            • 1970-01-01
            • 2017-11-21
            • 2014-07-15
            • 2020-11-24
            • 2020-05-26
            • 1970-01-01
            相关资源
            最近更新 更多