【问题标题】:What advantage is provided by object overloading in PHP?PHP 中的对象重载有什么好处?
【发布时间】:2009-08-11 20:29:03
【问题描述】:

PHP 对象重载解释here。

基本上,它允许您在访问不可访问的对象属性或方法时定义一些自定义操作。

此功能有哪些实际用途?

【问题讨论】:

    标签: php object


    【解决方案1】:

    通常,当您与第 3 方 API 通信或方法/成员结构不明确时,这些方法很有用。

    假设您正在编写一个通用的 XML-RPC 包装器。由于在下载 WDL 文件之前您不知道可用的方法,因此使用重载是有意义的。

    然后,而不是编写以下内容:

    $xmlrpc->call_method('DoSomething', array($arg1, $arg2));
    

    你可以使用:

    $xmlrpc->DoSomething($arg1, $arg2);
    

    这是一种更自然的语法。


    你也可以使用成员重载,就像变量对象的方法重载一样。

    您只需要注意一件事:将其仅用于可变结构对象或仅将其用于 getter 和 setter 的语法快捷方式。在您的类中保留 getter 和 setter 以在多个方法中分离业务逻辑是有意义的,但是将其用作快捷方式并没有错:

    class ShortcutDemo {
      function &__get($name) {
        // Usually you want to make sure the method
        // exists using method_exists, but for sake
        // of simplicity  of this demo, I will omit
        // that logic.
        return call_user_method('get'.$name, $this);
      }
    
      function __set($name, &$value) {
        return call_user_method('set'.$name, $this, $value);
      }
    
      private $_Name;
    
      function &getName() { return $this->_Name; }
      function setName(&$value) { $this->_Name = $value; }
    }
    

    这样您就可以继续使用您的 getter 和 setter 来验证和设置您的数据,并且仍然使用这样的语法快捷方式:

    $shortcut->Name = 'Hello';
    

    【讨论】:

      【解决方案2】:

      另一个 Andrew 没有提到(或在撰写本文时没有提到)的方法是摆脱 getter 和 setter。不必像这样声明每个 setter 和 getter:

      $obj->setName("Chacha");
      $obj->setRep(10000000000000000000000);
      

      你可以这样做

      $obj->Name = "chacha";
      $obj->Rep = 100000000000000000;
      

      第二种方法更自然。

      Magic Methods 基本上进一步推进了面向对象编程的思想,以及如何实现工作对外界而言并不重要的思想。通过魔术方法,它允许您随意存储变量,并让其他类以自然的方式设置它们。

      示例:我可以将所有用户的帐户首选项存储在一个数组中,这样可以很容易地进行迭代以将其全部推送到会话中。

      如果我不为此使用魔法方法,我将不得不制作一堆集合或获取,这意味着编写更多代码,或者允许直接访问数组,这揭示了实现,所以我可以以后别去改了。

      相反,使用魔术方法,我只是让他们定期设置变量,然后我在内部处理它。

      【讨论】:

      • 虽然我还没有摆脱 getter 和 setter。包含各种单独属性的业务规则的多个方法通常比一个包含所有属性的所有业务规则的巨大方法更容易维护和调试。我只会使用__get() 和__set() 作为调用getX、setX 的快捷方式。对象重载使用必须只用于可变结构对象。
      • 但是,这并不像 C# Get/Set Property 那样真正起作用。如果您希望验证或验证正在设置的内容,至少没有那么灵活。
      【解决方案3】:

      当一个类有复杂的 isset 和 unset 规则时,您可以使用它。例如,包含变量 $a 的类可以是对象数组或其他资源,当未设置时,它们必须执行一些其他功能。

      虽然我不确定他们为什么允许添加新属性和检索非私有属性,但您可以使用它来更改对象的内部状态,方法是根据属性名称调用其他代码/成员变量被设置。

      在某些情况下,这类似于 C++ 中的运算符重载

      【讨论】:

        【解决方案4】:

        消息转发适用于当您组合或聚合对象时不能选择多态性(例如,您正在使用无法控制的库类)。

        <?php
        
        // Class A is final, so we can't make subclasses.
        final class A
        {
          public function hello( $callback )
          {
            echo call_user_func( $callback, 'hello world' );
          }
        }
        
        // so instead, we make a wrapper class that will take an instance
        // of A as an aggregate
        class B
        {
          private $a;
        
          public function __construct( A $a )
          {
            $this->a = $a;
          }
        
          // this mimics inheritance on the aggregate object
          // method calls are automatically forwarded to instance of A
          // if they are valid
          public function __call( $method, $args )
          {
            if ( method_exists( $this->a, $method ) )
            {
              return call_user_func_array( array( $this->a, $method ), $args );
            }
            throw new Exception( "Method [$method] not found." );
          }
        }
        
        class C extends B
        {
          // This mimics overriding an "inherited" method
          public function hello( $callback )
          {
            echo call_user_func( $callback, 'bonjour le monde' );
          }
        }
        
        $a = new A;
        
        $b = new B( $a );
        $c = new C( $a );
        
        $b->hello( 'strtoupper' );
        $c->hello( 'strtoupper' );
        

        【讨论】:

          【解决方案5】:

          这个功能实际上是what object oriented programming is all about,在其发明者 Alan Kay 的心目中:对象相互发送消息,并可能对任何类型的消息做出反应。在编译时固定的方法是这个概念的有限(但也更有效)实现。这就是 Kay 的名言“我发明了面向对象的术语,我可以告诉你 C++ 不是我的想法。”来自。

          基本上,允许对象对方法调用做出反应,而无需在编译时固定相应的方法,这实现了面向对象的原始、更广泛的定义。大多数现代“动态”语言都以一种或另一种形式支持它。

          至于它的好处:看看Groovy's Builders 的一个很好的例子。基本上,它通过将方法名称本身转换为数据来实现非常紧凑的低冗余语法。

          【讨论】:

            【解决方案6】:

            我使用过的一种方法是创建一个类似于对象关系管理 (ORM) 的 Linq 系统,这有点儿花哨。然后,您可以在其中加载数据库表结构并(从数据库表中)操作数据,就好像它只是一个对象一样。

            即

            include('blibrary/bLinq.class.inc');
            
            $linq = new bLinq(new bLinqSql('mysql://dsn'));
            $r = $linq->from('Users')
                      ->password
                      ->select();
            

            转换为以下 SQL:

            SELECT `password` from Users;
            

            select语句中的password来自于重载的方法。

            结果可以这样使用:

            (array)$r->password;   // which outputs an array multiple results of password;
            (string)$r->password;  // which outputs a string of the first password hash;
            $r->password[2];       // which outputs a string of the third password hash;
            

            关键是在编程时,“password”这个词可以动态替换数据库中的任何其他字段。

            【讨论】:

              【解决方案7】:

              我使用 __get 和 __set 将对象链接在一起,例如

              $user = new User();
              echo $user->Profile->views;
              

              这(通常)调用一些 SQL 链接 users.id = profile.user_id。

              【讨论】:

                【解决方案8】:

                属性(如 Python 或 C# 中的属性)。例如,当您使用类似 in Nette 的东西时,您会创建一些类,它将某些属性显示为公共:

                <?php
                class Foo extends Object
                {
                    public $bar;
                }
                

                您可以通过自然方式访问此属性 - $instance-&gt;bar。但是当你想做一些验证等时,你只需添加 getter 和 setter:

                <?php
                class Foo extends Object
                {
                    private $bar;
                
                    public function getBar()
                    {
                        return $this->bar;
                    }
                
                    public function setBar($bar)
                    {
                        if ($bar === NULL) throw new Exception('…');
                        $this->bar = $bar;
                    }
                }
                

                你仍然使用$instance-&gt;bar。但是当你调用$instance-&gt;bar = NULL; 时,就像调用$instance-&gt;setBar(NULL);。

                【讨论】:

                  猜你喜欢
                  • 2012-10-09
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-08-18
                  • 1970-01-01
                  • 2010-11-23
                  • 1970-01-01
                  • 2011-10-12
                  相关资源
                  最近更新 更多