php create class method at runtime

Yes, you can.

Below is the way to create method in runtime in php 5.4.x.

The anonymous function is represented by Closure class started from 5.3.x. From 5.4.x, it add a Closure::bind static method to bind the anonymous function to a particular object or class.

Example:

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();

This is possible with the runkit extension's runkit_method_add(). Be careful using this in production though.

Example:

<?php
class Example {}

$e = new Example();

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

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

Did some playing around with whole thing. Seems that only thing you can potentially do with ReflectionClass is to replace an existing method. But even that would be indirectly.

I actually do not know any class-based language, where dynamic classes exist (then again, my knowledge is quite limited). I have seen it done only in prototype-based languages (javascript, ruby, smalltalk). Instead what you can do, in PHP 5.4, is to use Closure and add new methods to an existing object.

Here is a class which would let you perform such perversion to any 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
                );
        }
    }   
}

To use this, you have to provide constructor with an existing object. Here is small example of usage:

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'

Not exactly what you want, but AFAIK this is as close you can get.


Have you taken a look at create_function() in the docs? You might also achieve the desired result by overloading.

Tags:

Php

Reflection