Search code examples
phpmagic-methods

__callStatic not being called


Not sure why but Its not even hitting the var_dump() that I have. Lets look at how I have it implemented.

<?php

namespace ImageUploader\Controllers;

class ApplicationController implements \Lib\Controller\BaseController {
    ....

    public function beforeAction($actionName = null, $actionArgs = null){}

    public function afterAction($actionName = null, $actionArgs = null){}

    public static function __callStatic($name, $args) {
        var_dump('hello?'); exit;
        if (method_exists($this, $name)) {
            $this->beforeAction($name, $args);
            $action = call_user_func(array($this, $name), $args);
            $this->afterAction($name, $args);
            return $action;
        }
    }
}

As we can see I want to do something before and after an action is called, regardless if you implemented the method or not. But that var_dump is never reached.

This class is extended in:

<?php

namespace ImageUploader\Controllers;

use \Freya\Factory\Pattern;

class DashboardController extends ApplicationController  {

    public function beforeAction($actionName = null, $actionArgs = null) {
        var_dump($actionName, $actionArgs); exit;
    }

    public static function indexAction($params = null) {
      Pattern::create('\Freya\Templates\Builder')->renderView(
          'dash/home',
          array(
              'flash' => new \Freya\Flash\Flash(),
              'template' => Pattern::create('\Freya\Templates\Builder')
          )
      );
    }

    ....

}

Now when I do: DashboardController::indexAction(); it should exit ... unless I am missing something. If that's the case - what is it?

even the var_dump in the before_action(...) that's implemented is never reached (obvi' because of the first one, but if I take out the first one the second is never reach.)


Solution

  • __callStatic is called only when a static method does not exist - as indexAction actually is defined, it is executed without bothering __callStatic(). (Documentation)

    An approach to achieve what you are trying to do could be by wrapping your controller inside a decorator:

    class ExtendedApplicationController
    {
        /**
         * @var \Lib\Controller\BaseController
         */
        protected $controller;
    
        function __construct(\Lib\Controller\BaseController $controller) {
           $this->controller = $controller;
        }
    
        function __callStatic($name, $args) {
            if (method_exists($this->controller, 'beforeAction')) {
                call_user_func_array(array($this->controller, 'beforeAction'), $name, $args);
            }
    
            call_user_func_array(array($this->controller, $name), $args);
    
            if (method_exists($this->controller, 'afterAction')) {
                call_user_func_array(array($this->controller, 'afterAction'), $name, $args);
            }
        }
    }
    

    and then, in your code, you could do:

    $controller = new ExtendedApplicationController(new DashboardController());
    $controller::indexAction();
    

    I have to warn you that I didn't test this approach while I was writing it, but I hope it gives you an idea!