【问题标题】:Defining class methods in PHP在 PHP 中定义类方法
【发布时间】:2010-09-09 10:42:26
【问题描述】:

是否可以在PHP (as it is in C++) 中声明class method OUTSIDE class definition?

【问题讨论】:

  • 据我所知,您的要求在 C++ 中是不可能的。你可能想澄清一下。
  • 在 C++ 中,您可以在类之外定义函数,如果第一个参数属于该类类型,那么您会得到看起来像重载的东西(即显式的“this”)。例如,该方法用于诸如 std::cout 的

标签: php class


【解决方案1】:

不,从 PHP 5.2 开始。但是,您可以使用__call 魔术方法将调用转发到任意函数或方法。

class A {

    public function __call($method, $args) {
        if ($method == 'foo') {
            return call_user_func_array('bar', $args);
        }
    }

}

function bar($x) {
    echo $x;
}

$a = new A();
$a->foo('12345'); // will result in calling bar('12345')

在 PHP 5.4 中支持 traits。 Trait 是不能作为独立对象实例化的方法的实现。相反,特征可用于扩展具有包含实现的类。详细了解 Traits here

【讨论】:

    【解决方案2】:

    是的,可以在定义 PHP 类后添加一个方法。您想使用classkit,这是一个“实验性”扩展。但是,默认情况下似乎未启用此扩展,因此这取决于您是否可以在 Windows 上编译自定义 PHP 二进制文件或加载 PHP DLL(例如 Dreamhost 确实允许自定义 PHP 二进制文件,并且它们很容易设置)。

    <?php
    class A { }
    classkit_method_add('A', 'bar', '$message', 'echo $message;', 
        CLASSKIT_ACC_PUBLIC); 
    $a = new A();
    $a->bar('Hello world!');
    

    PHP 手册中的示例:

    <?php
    class Example {
        function foo() {
            echo "foo!\n";
        }
    }
    
    // create an Example object
    $e = new Example();
    
    // Add a new public method
    classkit_method_add(
        'Example',
        'add',
        '$num1, $num2',
        'return $num1 + $num2;',
        CLASSKIT_ACC_PUBLIC
    );
    
    // add 12 + 4
    echo $e->add(12, 4);
    

    【讨论】:

    【解决方案3】:

    您或许可以覆盖__call or __callStatic 以在运行时定位缺失的方法,但您必须构建自己的系统来定位和调用代码。例如,您可以加载一个“Delegate”类来处理方法调用。

    这是一个例子 - 如果你试图调用 $foo->bar(),该类将尝试创建一个 FooDelegate_bar 类,并使用相同的参数对其调用 bar()。如果您设置了类自动加载,则委托可以保存在单独的文件中,直到需要...

    class Foo {
    
        public function __call($method, $args) {
            $delegate="FooDelegate_".$method;
            if (class_exists($delegate))
            {
                 $handler=new $delegate($this);
                 return call_user_func_array(array(&$handler, $method), $args);
            }
    
    
        }
    
    }
    

    【讨论】:

      【解决方案4】:

      由于 PHP 5.3 支持闭包,您可以将实例方法动态定义为持有闭包的变量:

      $class->foo = function (&$self, $n) {
        print "Current \$var: " . $self->var . "\n";
        $self->var += $n;
        print "New \$var:     " .$self->var . "\n";
      };
      

      $self(不能在对象上下文之外使用$this)作为引用(&amp;),可以修改实例。

      但是,当您尝试正常调用该函数时会出现问题:

      $class->foo(2);
      

      你得到一个致命错误。 PHP 认为foo$class 的一个方法,因为它的语法。此外,您必须将实例作为第一个参数传递。

      幸运的是,有一个名为call_user_func 的特殊函数用于按名称调用函数:

      call_user_func($class->foo, &$class, 2);
      # => Current $var: 0
      # => New $var:     2
      

      记得在实例变量之前加上&amp;

      如果你使用__call魔术方法,那就更简单了:

      class MyClass {
        public function __call ($method, $arguments)  {
          if (isset($this->$method)) {
            call_user_func_array($this->$method, array_merge(array(&$this), $arguments));
          }
        }
      }
      

      现在您可以致电$class-&gt;foo(2)。神奇的__call 方法捕获对未知方法的调用,并调用与被调用方法同名的$class-&gt;foo 变量中的闭包。

      当然,如果$class-&gt;var 是私有的,则存储在$class-&gt;foo 变量中的闭包将无法访问它。

      【讨论】:

      • 请注意,在 PHP 中调用函数时使用 & 是不合法的。它在不久前被接受(在 PHP 4 中可能是必需的),但今天当您运行该代码 call_user_func($class-&gt;foo, &amp;$class, 2); 时会收到警告或错误。
      • 我知道。之前有必要
      • 此外,在最新的 PHP 版本中,您可以在闭包中使用 $this。
      【解决方案5】:

      没有。

      不过,如果有帮助,您可以扩展之前声明的类。

      【讨论】:

        【解决方案6】:

        不,这是不可能的。如果您在类构造之外定义函数/方法,它将成为全局函数。

        【讨论】:

        • 在类之外定义的所有函数都不是全局的。如果将函数保存在变量中,则它不是全局的。 ($func = function() {...};)
        【解决方案7】:

        C++ 也无法做到这一点。您是否将声明与定义混淆了?

        【讨论】:

          【解决方案8】:

          不,正如大家所说的那样,严格来说是不可能的。

          但是,您可以使用something like this 来模拟 PHP 中的 mixin 或在运行时向类添加方法,这与您将获得的差不多。基本上,它只是使用设计模式来实现相同的功能。 Zope 3 做了类似于在 Python 中模拟 mixins,另一种不直接支持它们的语言。

          【讨论】:

          • 您关于 Python 的说法不正确,因为 Python 确实支持多重继承,并且确实支持在运行时定义方法。
          猜你喜欢
          • 1970-01-01
          • 2012-10-10
          • 1970-01-01
          • 1970-01-01
          • 2015-08-25
          • 1970-01-01
          • 2013-10-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多