flightphp / core

An extensible micro-framework for PHP
https://docs.flightphp.com
MIT License
2.63k stars 407 forks source link

Fix Dispatcher::invokeMethod to allow for named params #458

Closed ghost closed 2 years ago

ghost commented 2 years ago

Currently, Flight appears to break when using named parameters when calling static methods. For example:

Flight::set('flight.views.path', __DIR__.'/../src/UI/views');

Flight::route('GET /', function () {
    Flight::render('UI_VIEW_MOCKUP', key: 'main_content');  // breaks
    Flight::render('basic_layout');
});

Flight::start();

This appears to be due to the switch statement in Dispatcher::invokeMethod that is assuming a numerically-indexed array as the params argument:

   /**
     * Invokes a method.
     *
     * @param mixed $func   Class method
     * @param array $params Class method parameters
     *
     * @return mixed Function results
     */
    public static function invokeMethod($func, array &$params = [])
    {
        [$class, $method] = $func;

        $instance = \is_object($class);

        switch (\count($params)) {
            case 0:
                return ($instance) ?
                    $class->$method() :
                    $class::$method();
            case 1:
                return ($instance) ?
                    $class->$method($params[0]) :
                    $class::$method($params[0]);
            case 2:
                return ($instance) ?
                    $class->$method($params[0], $params[1]) :
                    $class::$method($params[0], $params[1]);
            case 3:
                return ($instance) ?
                    $class->$method($params[0], $params[1], $params[2]) :
                    $class::$method($params[0], $params[1], $params[2]);
            case 4:
                return ($instance) ?
                    $class->$method($params[0], $params[1], $params[2], $params[3]) :
                    $class::$method($params[0], $params[1], $params[2], $params[3]);
            case 5:
                return ($instance) ?
                    $class->$method($params[0], $params[1], $params[2], $params[3], $params[4]) :
                    $class::$method($params[0], $params[1], $params[2], $params[3], $params[4]);
            default:
                return \call_user_func_array($func, $params);
        }
    }

If we just use call_user_func_array()—which the switch statement already defaults to—this problem disappears:

   /**
     * Invokes a method.
     *
     * @param mixed $func   Class method
     * @param array $params Class method parameters
     *
     * @return mixed Function results
     */
    public static function invokeMethod($func, array &$params = [])
    {
        return \call_user_func_array($func, $params);
    }

EDIT: A similiar fix was needed for Dispatcher::callFunction(...):

/**
     * Calls a function.
     *
     * @param callable|string $func   Name of function to call
     * @param array           $params Function parameters
     *
     * @return mixed Function results
     */
    public static function callFunction($func, array &$params = [])
    {
        return \call_user_func_array($func, $params);
    }