Shadow Walker
Shadow Walker

Reputation: 335

How to add methods dynamically

I'm trying to add methods dynamically from external files. Right now I have __call method in my class so when i call the method I want, __call includes it for me; the problem is I want to call loaded function by using my class, and I don't want loaded function outside of the class;

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

echoA.php:

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

then i want to use it like:

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

Any advice will be appreciated.

Upvotes: 23

Views: 21482

Answers (10)

Hugo R
Hugo R

Reputation: 3113

You can do both adding methods and properties dynamically.

Properties:

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;

Methods:

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

Upvotes: 0

Solo.dmitry
Solo.dmitry

Reputation: 780

Maybe a closure will help you.

UPD: Yes, guys, I was wrong. Even we convert named function to closure, there will be error of binding context. I did not pay attention that TS has ready external functions. But my link can be useful for those peoples, who get here after googled how to call SOME THEIR code inside class's instance's scope. I used myself Reflection to do this until met and tried Closure.

Upvotes: -1

Jared Farrish
Jared Farrish

Reputation: 49238

/**
 * @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

Upvotes: 0

Madara's Ghost
Madara's Ghost

Reputation: 175088

What you are referring to is called Overloading. Read all about it in the PHP Manual

Upvotes: 0

Thinol
Thinol

Reputation: 55

You can dynamically add attributes and methods providing it is done through the constructor in the same way you can pass a function as argument of another function.

class Example {
    function __construct($f)
    {
       $this->action=$f;
    }
}

function fun() {
   echo "hello\n";
}

$ex1 = new class('fun');

You can not call directlry $ex1->action(), it must be assigned to a variable and then you can call this variable like a function.

Upvotes: 5

Pavel Hanpari
Pavel Hanpari

Reputation: 4744

Is this what you need?

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

Upvotes: 19

Matrix
Matrix

Reputation: 3369

You can create an attribute in your class : methods=[]
and use create_function for create lambda function.
Stock it in the methods attribute, at index of the name of method you want.
use :

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

to find and call good method.

Upvotes: 0

Mark Howells-Mead
Mark Howells-Mead

Reputation: 229

I've worked up the following code example and a helper method which works with __call which may prove useful. https://github.com/permanenttourist/helpers/tree/master/PHP/php_append_methods

Upvotes: -3

deceze
deceze

Reputation: 522510

You cannot dynamically add methods to a class at runtime, period.*
PHP simply isn't a very duck-punchable language.

* Without ugly hacks.

Upvotes: 14

Puggan Se
Puggan Se

Reputation: 5846

if i read the manual right, the __call get called insted of the function, if the function dosn't exist so you probely need to call it after you created it

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

Upvotes: 3

Related Questions