Вопрос по reflection, php – PHP создать метод класса во время выполнения

24

Мне интересно, есть ли способ присоединить новый метод к классу во время выполнения, в php. Я имею в виду, не на уровне экземпляра, а непосредственно в классе, чтобы у всех вновь создаваемых экземпляров был этот новый метод. Можно ли сделать такую вещь с помощью отражения?

Спасибо

Ваш Ответ

4   ответа
3

create_function () в документах? Вы также можете достичь желаемого результата путемперегрузка.

Я понимаю. PHP, однако, не такой динамичный язык, как было бы идеально в этом сценарии. я верюReflection или жеRunkit было бы необходимо найти более близкое решение, на которое вы ссылались в своем вопросе.
Вы можете рассмотретьthis blog post или жеthis one а такжеthis SO question для дополнительной информации.
@ Томас, с сомнением. Поскольку PHP является базой классов, а не языком прототипов.
Я хотел бы найти решение с помощью размышлений, но я не могу найти информацию где-либо. Глядя на API, я ничего не могу использовать Thomas
create_function (насколько я знаю) создает функции в глобальном контексте, а перегрузка - не такое чистое решение, как хотелось бы Thomas
21

Ниже приведен способ создания метода во время выполнения в php 5.4.x.

Анонимная функция представлена классом Closure, запущенным из 5.3.x. Начиная с 5.4.x, он добавляетЗакрытие :: привязывать статический метод для привязки анонимной функции к определенному объекту или классу.

Пример:

class Foo {
     private $methods = array();

     public function addBar() {
       $barFunc = function () {
         var_dump($this->methods);
       };
       $this->methods['bar'] = \Closure::bind($barFunc, $this, get_class());
     }

     function __call($method, $args) {
          if(is_callable($this->methods[$method]))
          {
            return call_user_func_array($this->methods[$method], $args);
          }
     }
 }

 $foo = new Foo;
 $foo->addBar();
 $foo->bar();
Какой смысл здесь в методе __call, если \ Closure :: bind делает это, и наоборот?
Потрясающие. Люблю эти новые функции PHP Thomas
@jayarjo\Closure::bind изменяет контекст анонимной функции (в этом случае он гарантирует, что в закрытии$this относится к правильному объекту). Однако это не превращает эту функцию в метод$this, Нам еще нужно__call чтобы позволить внешнему коду вызывать замыкание, как если бы это был метод.
8

что единственное, что вы можете сделать потенциальноReflectionClass это заменить существующий метод. Но даже это будет косвенным.

Я на самом деле не знаю ни одного языка на основе классов, где бывают динамические классы (опять же, мои знания весьма ограничены). Я видел, как это делается только на прототипных языках (javascript, ruby, smalltalk). Вместо того, что вы можете сделать, вPHP 5.4, это использоватьClosure и добавить новые методы вexisting object.

Вот класс, который позволит вам выполнить такое извращение для любого объекта:

class Container
{
    protected $target;
    protected $className;
    protected $methods = [];

    public function __construct( $target )
    {
        $this->target = $target;
    }

    public function attach( $name, $method )
    {
        if ( !$this->className )
        {
            $this->className = get_class( $this->target );
        }
        $binded = Closure::bind( $method, $this->target, $this->className );
        $this->methods[$name] = $binded;
    }

    public function __call( $name, $arguments )
    {
        if ( array_key_exists( $name, $this->methods ) )
        {
            return call_user_func_array( $this->methods[$name] , $arguments );
        }

        if ( method_exists( $this->target, $name ) )
        {
            return call_user_func_array( 
                array( $this->target, $name ),
                $arguments
                );
        }
    }   
}

Чтобы использовать это, вы должны предоставить конструктору существующий объект. Вот небольшой пример использования:

class Foo
{
    private $bar = 'payload';
};
$foobar = new Foo;
// you initial object


$instance = new Container( $foobar );
$func = function ( $param )
{
    return 'Get ' . $this->bar . ' and ' . $param;
};
$instance->attach('test', $func);
// setting up the whole thing


echo $instance->test('lorem ipsum');
// 'Get payload and lorem ipsum'

Не совсем то, что вы хотите, но AFAIK это как можно ближе.

3

runkit_method_add (), Будьте осторожны, используя это в производстве.

Пример:

<?php
class Example {}

$e = new Example();

runkit_method_add(
    'Example',
    'add',
    '$num1, $num2',
    'return $num1 + $num2;',
    RUNKIT_ACC_PUBLIC
);

echo $e->add(12, 4);

Похожие вопросы