【问题标题】:php class function wrapperphp类函数包装器
【发布时间】:2012-04-11 16:06:25
【问题描述】:

这是我的课:

class toyota extends car {
    function drive() {
    }
    function break() {
    }
}

class car {
    function pre() {
    }
}

有什么方法可以让我在运行 $car->drive()、$car->break()(或丰田中的任何其他函数)时,首先调用 $car->pre()在调用 toyota 中的函数之前?

【问题讨论】:

  • 阅读“构造函数”函数......这可能是你需要的。
  • 你能澄清一下吗?我不知道你是否想在创建新对象时运行 $car->pre(),或者在调用 $car 方法的任何时候。下面的答案涵盖了两者 - 我只是不知道要修改哪一个。

标签: php oop


【解决方案1】:

是的。你可以使用protected 和一些__call 魔法:

class toyota extends car {
    protected function drive() {
        echo "drive\n";
    }
    protected function dobreak() {
        echo "break\n";
    }
}

class car {
    public function __call($name, $args)
    {
        if (method_exists($this, $name)) {
            $this->pre();
            return call_user_func_array(array($this, $name), $args);
        }


    }

    function pre() {
        echo "pre\n";
    }
}

$car = new toyota();
$car->drive();
$car->dobreak();

http://ideone.com/SGi1g

【讨论】:

  • 这不仅是唯一使用 __call 的答案(正确的方法),而且它也是唯一一个实际执行一些 method_exists 检查并实际调用最初调用的方法的方法。这样做!
  • 你的意思是私有的而不是受保护的?因为受保护的父母仍然可以看到和继承。
  • @sberry,使用 method_exists() 检查会隐藏调用无效方法时收到的默认错误
  • @Starx:是的,但是如果方法不存在,您可能会抛出本机错误或异常
  • @Patrick: 不,private 不起作用,因为父类无法访问祖先的私有方法
【解决方案2】:

您可以执行以下操作,但我认为这不是您想要的。

class toyota extends car {
    function drive() {
         $this->pre();
    }
    function break() {
         $this->pre();
    }
}

class car {
    function pre() {
    }
}

您可能想研究 PHP 特定的魔术方法。 http://php.net/manual/en/language.oop5.magic.php

【讨论】:

    【解决方案3】:

    使用称为 __call() 的魔术方法会更好

    public function __call($name, $arguments)
    {
        $this -> pre();
        return $this -> $name($arguments);
    }
    

    这个方法是什么?它覆盖了默认的方法调用,从而可以调用preCall状态。

    你的toyota 班级

    class toyota extends car {    
    
        public function __call($name, $arguments)
        {
            $this -> pre();
            return call_user_func_array(array($this, $name), $arguments);
        }
    
        function drive() {
        }
        function break() {
        }
    }
    

    【讨论】:

    • $this -> $name($arguments) --- 将调用请求的方法,并将所有参数作为数组传递。所以$car->drive(1, 2) 会被$car->drive(array(1, 2)) 重新调用,这是不正确的
    【解决方案4】:

    如果您使用的是 PHP5 (>=5.3.2),有一个解决方案可以将所有方法声明为私有。这将强制从单个函数调用中调用方法:

    exec_method()
    

    运行地址:http://ideone.com/cvfCXm

    代码sn-p在这里:

    <?php
    
        class car {
    
            //method to get class method
            public function get_method($method_name) {
                $class = new ReflectionClass(get_class($this));
                $method = $class->getMethod($method_name);
                $method->setAccessible(true);
                return $method;
            }
    
            public function exec_method($method_name, $arg_args=array()) {
    
                //execute the pre() function before the specified method
                $this->pre();
    
                //execute the specified method
                $this->get_method($method_name)->invokeArgs($this, $arg_args);
            }
    
            public function pre() {
                echo 'pre';
                echo '<br />';
            }
        }
    
        class toyota extends car {
            private function drive() {
                echo 'drive';
                echo '<br />';
            }
    
            private function brake() {
                echo 'brake';
                echo '<br />';
            }
        }
    
        $toyota = new toyota();
        $toyota->exec_method('drive');
        $toyota->exec_method('brake');
    ?>
    

    参考:

    Answer to Best practices to test protected methods with PHPUnit [closed]

    【讨论】:

      【解决方案5】:

      只需添加一个constructor,就像这样...

      class toyota extends car {
          function __construct() { 
              $this->pre();
          }   
      
          function drive() {
              echo "drive!";
          }
      
          function dobreak() {
              echo "break!";
          }
      }
      
      class car {
          function pre() {
              echo "Hello!";
          }
      }
      
      $car = new toyota();
      $car->drive();
      $car->dobreak();
      

      具有构造方法的类在每个类上调用此方法 新创建的对象,因此它适用于任何初始化 对象在使用之前可能需要。

      break 是保留的,因此不应将其用作函数名。

      【讨论】:

      • 我认为他正在寻找一种在函数调用之前运行方法 pre 的方法,而不是在对象初始化时运行
      • 在回复时我被打断了。我已经用构造函数更新了我的示例。它仍然可以工作。
      猜你喜欢
      • 2018-10-16
      • 2021-11-24
      • 2021-02-27
      • 2021-04-06
      • 1970-01-01
      • 2017-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多