Search code examples
javaphprunnableportingcommand-pattern

How to migrate a java command pattern using runnable to PHP 7.4?


For studying purpose, I am trying to migrate this Java Command Pattern example to PHP:

https://codereview.stackexchange.com/questions/52110/command-pattern-implementation

UML diagram

As @simon commented, using method reference operator, would modernize quite a bit the code:

class MyCommand implements Order {
    private final Runnable action;

    public MyCommand(Runnable action) {
         this.action = action;
    }

    @Override
    public void execute() {
         action.run();
    }
}

And then you could create commands like this:

MyCommand bsc = new MyCommand(stock::buy);
MyCommand ssc = new MyCommand(stock::sell);

My current PHP implementation is here: https://3v4l.org/iIHn9

So what is the best approach to implement the MyCommand Class in PHP?


Solution

  • As Evgeniy already mentioned you can use call_user_func().

    Since there is many ways how to solve this I've added my solutions to your question. You can also make an object callable by adding the __invoke method inside a class. It's also possible to return a callable function. I've added in total 3 examples for it.

    This is my version of your MyCommand class in java which is used for all 3 examples.

    class MyCommand implements Order
    {
        private $action;
    
        public function __construct(callable $action)
        {
            $this->action = $action;
        }
    
        public function execute()
        {
            // Option 1) use call_user_function
            call_user_func($this->action);
    
            // Option 2) define it as a variable and call it by adding `()`
            //$action = $this->action;
            //$action();
        }
    }
    

    Example 1) A callable function (https://3v4l.org/FVTEK)

    class Stock
    {
        public function buy(): callable
        {
            return function () {
                echo "You want to buy stocks via callable function" . PHP_EOL;
            };
        }
    
        public function sell(): callable
        {
            return function () {
                echo "You want to sell stocks via callable function" . PHP_EOL;
            };
        }
    }
    
    $stock = new Stock();
    $bsc = new MyCommand($stock->buy());
    $ssc = new MyCommand($stock->sell());
    
    $bsc->execute();
    $ssc->execute();
    

    Example 2) A callable class (https://3v4l.org/BrKjv)

    class StockBuy
    {
        public function __invoke()
        {
            echo "You want to buy stocks via __invoke()" . PHP_EOL;
        }
    }
    
    class StockSell
    {
        public function __invoke()
        {
            echo "You want to sell stocks __invoke()" . PHP_EOL;
        }
    }
    
    $bsc = new MyCommand(new StockBuy());
    $ssc = new MyCommand(new StockSell());
    
    $bsc->execute();
    $ssc->execute();
    

    Example 3) Static member functions which return callable. Just an example to be more close to java (https://3v4l.org/PKk4B)

    class Stock
    {
        static public function buy(): callable
        {
            return function () {
                echo "You want to buy stocks via callable function" . PHP_EOL;
            };
    
            // or as callable object
            // return new StockBuy();
        }
    
        static public function sell(): callable
        {
            return function () {
                echo "You want to sell stocks via callable function" . PHP_EOL;
            };
    
            // or as callable object
            // return new StockSell();
        }
    }
    
    $bsc = new MyCommand(Stock::buy());
    $ssc = new MyCommand(Stock::sell());
    $bsc->execute();
    $ssc->execute();
    

    Please let me know if you have any further questions.