PHP | Change function inside class

133 Views Asked by At

I want to create a daemon constructor in PHP.

class DAEMON {
    var host;
    var port;
    function __construct($host, $port) {
        $this -> host = $host;
        $this -> port = $port;
    }
    function start() {
        while (true) {
            $this->loop();
        }
    }
    function loop() {

    }
}

In addition to passing the $host and $port parameters like

$server = new DAEMON("127.0.0.1", 9000);
$server -> start();

I want somehow to pass the loop() function as a 3rd parameter, so it overwrites the loop() function or inject code inside it.

I have tried

$server = new DAEMON("127.0.0.1", 9000, function() {
    // function() can't take any parameters
    // I cant use $server variable here
});
$server -> start();

and

$server = new DAEMON("127.0.0.1", 9000);
$server::loop = function() {
    //not working, it's not javascript
};
$server->start();

Neither work. How can I do it? I have struggled many hours trying to find a solution..

3

There are 3 best solutions below

2
On

You can call the use language construct to pass arguments to the anonymous functions. In your case, if you wanted to use the $server variable, then you could do ..

$server = new DAEMON("127.0.0.1", 9000, function() use ($server){
    // function() can't take any parameters
    // I cant use $server variable here
});
$server -> start();

... but for this to work, your DAEMON{} class should have a third parameter in the constructor that accepts callable type..

0
On

I am unsure on your actual reasons on allowing a function to run arbitrary code but you can do something really dirty by executing a string as php code .

class DAEMON {
    private $host;
    private $port;
    private $injection;

    public function __construct($host, $port, $injection) {
        $this->host = $host;
        $this->port = $port;
        $this->injection = $injection;
    }
    public function start() {
        while (true) {
            $this->loop();
        }
    }
    private function loop() {
        eval($this->injection);
    }
}
3
On

You can just pass a anonymous function to the constructor

http://php.net/manual/en/functions.anonymous.php

<?php

class DAEMON {
    private $host;
    private $port;
    private $callback;

    public function __construct($host, $port, $callback) {
        $this->host = $host;
        $this->port = $port;
        if ( ! is_callable($callback)) {
            throw new InvalidArgumentException('callback needs to be a function');
        }

        $this->callback = $callback;
    }

    public function start() {
        $callback = $this->callback;
        while (true) {
            $callback($this);
        }
    }
}

$server = new DAEMON("127.0.0.1", 9000, function($server) {
    echo "hello_world";
});

$server->start();