如何动态添加方法


How to add methods dynamically

我正在尝试从外部文件动态添加方法。现在我的类中有__call方法,所以当我调用我想要的方法时,__call会为我包含它;问题是我想用我的类来调用已加载的函数,而我不想在类之外调用已加载函数;

Class myClass
{
    function__call($name, $args)
    {
        require_once($name.".php");
    }
}

echoA.php:

function echoA()
{
    echo("A");
}

然后我想像一样使用它

$myClass = new myClass();
$myClass->echoA();

如有任何建议,我们将不胜感激。

这就是您需要的吗?

$methodOne = function ()
{
    echo "I am  doing one.".PHP_EOL;
};
$methodTwo = function ()
{
    echo "I am doing two.".PHP_EOL;
};
class Composite
{
    function addMethod($name, $method)
    {
        $this->{$name} = $method;
    }
    public function __call($name, $arguments)
    {
        return call_user_func($this->{$name}, $arguments);
    }
}

$one = new Composite();
$one -> addMethod("method1", $methodOne);
$one -> method1();
$one -> addMethod("method2", $methodTwo);
$one -> method2();

不能在运行时将方法动态添加到类中。*
PHP根本不是一种很容易被打掉的语言。

*没有丑陋的黑客

您可以动态添加属性和方法,只要它是通过构造函数完成的,就像您可以将函数作为另一个函数的参数传递一样。

class Example {
    function __construct($f)
    {
       $this->action=$f;
    }
}
function fun() {
   echo "hello'n";
}
$ex1 = new class('fun');

不能调用directlry $ex1->action(),必须将其分配给一个变量,然后才能像函数一样调用该变量。

如果我正确阅读了手册,如果函数不存在,则__call将调用函数的指令所以你可能需要在创建它之后将其称为

Class myClass
{
    function __call($name, $args)
    {
        require_once($name.".php");
        $this->$name($args);
    }
}

您可以在类中创建一个属性:methods=[]
并使用create_function创建lambda函数
将其存放在methods属性中,位于所需方法名称的索引处
用途:

function __call($method, $arguments)
{
   if(method_exists($this, $method))
      $this->$method($arguments);
   else
      $this->methods[$method]($arguments);
}

找到并调用好的方法。

您所指的称为重载。请参阅PHP手册

/**
 * @method Talk hello(string $name)
 * @method Talk goodbye(string $name)
 */
class Talk {
    private $methods = [];
    
    public function __construct(array $methods) {
        $this->methods = $methods;
    }
    
    public function __call(string $method, array $arguments): Talk {
        if ($func = $this->methods[$method] ?? false) {
            $func(...$arguments);
            
            return $this;
        }
        
        throw new 'RuntimeException(sprintf('Missing %s method.'));
    }
}
$howdy = new Talk([
    'hello' => function(string $name) {
        echo sprintf('Hello %s!%s', $name, PHP_EOL);
    },
    'goodbye' => function(string $name) {
        echo sprintf('Goodbye %s!%s', $name, PHP_EOL);
    },
]);
$howdy
    ->hello('Jim')
    ->goodbye('Joe');

https://3v4l.org/iIhph

您可以动态添加方法和属性。

属性:

class XXX
{
    public function __construct($array1)
    {
        foreach ($array1 as $item) {
            $this->$item = "PropValue for property : " . $item;
        }
    }
}
$a1 = array("prop1", "prop2", "prop3", "prop4");
$class1 = new XXX($a1);
echo $class1->prop1 . PHP_EOL;
echo $class1->prop2 . PHP_EOL;
echo $class1->prop3 . PHP_EOL;
echo $class1->prop4 . PHP_EOL;

方法:

//using anonymous function
$method1 = function () {
    echo "this can be in an include file and read inline." . PHP_EOL;
};
class class1
{
    //build the new method from the constructor, not required to do it here but it is simpler.
    public function __construct($functionName, $body)
    {
        $this->{$functionName} = $body;
    }
    public function __call($functionName, $arguments)
    {
        return call_user_func($this->{$functionName}, $arguments);
    }
}
//pass the new  method name and the refernce to the anounymous function
$myObjectWithNewMethod = new class1("method1", $method1);
$myObjectWithNewMethod->method1();

也许闭包会对您有所帮助。

UPD:是的,伙计们,我错了。即使我们将命名函数转换为闭包,也会出现绑定上下文的错误。我没有注意到TS有现成的外部功能。但我的链接对那些在谷歌上搜索了如何在类的实例范围内调用他们的代码后来到这里的人来说可能很有用。我用自己的反思来做这件事,直到遇到并尝试了闭包。

我已经制作了以下代码示例和一个与__call一起使用的助手方法,这可能会很有用。https://github.com/permanenttourist/helpers/tree/master/PHP/php_append_methods