'Must be of the type array, null given,

I keep getting the following error and I'm not to sure why:

Catchable fatal error: Argument 3 passed to System\Loader::action() must be of the type array, null given, called in /Application.php on line 31 and defined in /Loader.php on line 18

Loader class:

    <?php

namespace System;

class Loader{
    //application object 
    private $app;
    //controllers container of array
    private $controllers = [];
    //models container array
    private $models = [];
    //constructor takes in system/application $app
    public function __construct(Application $app){
        $this->app = $app;
    }
    //call the given controller with the given method and pass the given arguments to the controller method
    //takes in string $controller, string $method and array $arguements returns mixed
    public function action ($controller, $method, array $arguements){ ##line 18
        $object = $this->controller($controller);
        return call_user_func([$object, $method], $arguements);
    }
    //call the given controller takes in string $controller and returns object
    public function controller ($controller){
        $controller = $this->getControllerName($controller);
        if(! $this->hasController($controller)){
            $this->addController($controller);
        }
        return $this->getController($controller);
    }
    //determine if the given clas/controller exists in the controller container takes in string $controller and returns boolean
    private function hasController($controller){
        return array_key_exists($controller, $this->controllers);
    }
    //create new object for the given controller and store it in the controllers container
    //takes in string $controller and returns void
    private function addController($controller){
        $object = new $controller($this->app);
        $this->controllers[$controller] = $object;
    }
    //get the controller object takes in string $controller and returns object
    private function getController($controller){
        return $this->controllers[$controller];
    }
    //get the full class name for the given controller takes string $controller returns string
    private function getControllerName($controller){
        $controller .= 'Controller';
        $controller = 'App\\Controllers\\' . $controller;
        return str_replace('/', '\\', $controller);
    }

    //call the given Model takes in string $Model and returns object
    public function model ($model){
        $model = $this->getModelName($model);
        if(! $this->hasModel($model)){
            $this->addModel($model);
        }
        return $this->getModel($model);
    }
    //determine if the given clas/Model exists in the Model container takes in string $controller and returns boolean
    private function hasModel($model){
        return array_key_exists($model, $this->models);
    }
    //create new object for the given Model and store it in the controllers container
    //takes in string $Model and returns void
    private function addModel($model){
        $object = new $model($this->app);
        $this->models[$model] = $object;
    }
    //get the Model object takes in string $Model and returns object
    private function getModel($model){
        return $this->models[$model];
    }
    //get the full class name for the given Model takes string $Model returns string
    private function getModelName($model){
        $model .= 'Model';
        $model = 'App\\Models\\' . $model;
        return str_replace('/', '\\', $model);
    }

}

application class:

<?php

namespace System; 

class Application {
    //Container array var
    private $container = [];
    //application object 
    private static $instance;
    //constructor $file param
    private function __construct(File $file){
        $this->share('file', $file);
        $this->registerClasses();
        // static::$instance = $this;
        $this->loadHelpers();

    }
    //get application instance parameter $file returns system\application
    public static function getInstance($file = null){
        if(is_null(static::$instance)) {
            static::$instance = new static($file);
        }
        return static::$instance;
    }
    //run the application returns void
    public function run(){
        $this->session->start();
        $this->request->prepareUrl();
        $this->file->call('App/index.php');
        list($controller, $method, $arguments) = $this->route->getProperRoute();
        $output = (string) $this->load->action($controller, $method, $arguments); ##line 31
        $this->response->setOutput($output);
        $this->response->send();

    }
    //register classes in sql auto load register
    private function registerClasses(){
        spl_autoload_register([$this, 'load']);
    }
    //load class through autoloading takes string $class and returns void
    public function load($class){
        if(strpos($class, 'App') === 0){
            $file = $class . '.php';
        } else {
            //get the class from vendor
            $file = 'vendor/' . $class . '.php';
        }
        if($this->file->exists($file)){
            $this->file->call($file);   
        }
    }
    //load helpers file returns void
    private function loadHelpers(){
        $this->file->call('vendor/helpers.php');
    }
    // get shared value takes in string $key returns mixed
    public function get($key){
        if(! $this->isSharing($key)){
            if($this->isCoreAlias($key)){
                $this->share($key, $this->createNewCoreObject($key));
            } else{
                die('<b>' . $key . '</br> not found in application container');
            }
        }
        return $this->container[$key];
        // return $this->isSharing() ? $this->container[$key] : null;
    }
    //determind if the given key is shared through application takes string $key returns boolean
    public function isSharing($key){
        return isset($this->container[$key]);
    }
    //share key and value through application
    public function share($key, $value){
        $this->container[$key] = $value;
    }
    //determines if the given key is an alias to core class takes string $alias returns boolean
    public function isCoreAlias($alias){
        $coreClasses = $this->coreClasses();
        return isset($coreClasses[$alias]);
    }
    //create new object for the core class based on the given alias takes in string $alias returns object
    public function createNewCoreObject($alias){
        $coreClasses = $this->coreClasses();
        $object = $coreClasses[$alias];
        return new $object($this);
    }
//get all core classes with its aliase returns array
private function coreClasses(){
    return [
            'request'       => 'System\\Http\\Request', 
            'response'      => 'System\\Http\\Response', 
            'session'       => 'System\\Session',
            'route'         => 'System\\Route',
            'cookie'        => 'System\\Cookie',
            'load'          => 'System\\Loader',
            'html'          => 'System\\Html', 
            'db'            => 'System\\Database', 
            'view'          => 'System\\View\\ViewFactory',
            'url'           => 'System\\Url', 
    ];
}
//get shared value dynamically takes string $key returns mixed
public function __get($key){
    return $this->get($key);
}

}

Not too sure where its getting this null from would appreciate if someone could help me figure this out.

edit: route class

<?php

namespace System;

class Route {
    //application object 
    private $app;
    //routes container
    private $routes = [];
    //not found url 
    private $notFound;
    //constructor
    public function __construct(Application $app){
        $this->app = $app;
    }
    //add new route takes string $url string $action and string $requestmethod returns void
    public function add ($url, $action, $requestMethod = 'GET'){
        $route = [
            'url'       => $url,
            'pattern'   => $this->generatePattern($url),
            'action'    => $this->getAction($action),
            'method'    => strtoupper($requestMethod),
            ];
        $this->routes[] = $route;
    }   
    //set not found url take string $url returns void
    public function notFound($url){
        $this->notFound = $url;
    }
    //get proper route reutns array
    public function getProperRoute(){
        foreach ($this->routes as $route) {
            if ($this->isMatching($route['pattern'])){
                $arguments = $this->getArgumentsFrom($route['pattern']);
                list($controller, $method) = explode('@', $route['action']);
                return [$controller, $method, $arguments];
            }
        }
    }
    //determine if the given pattern matches the current requested url takes string $pattern returns boolean
    private function isMatching($pattern){ 
        return preg_match($pattern, $this->app->request->url());
    }
    // get arguement from the current requested url based on the given pattern takes in string $pattern returns array
    private function getArgumentsFrom($pattern){
        preg_match($pattern, $this->app->request->url(), $matches);
        array_shift($matches);
        return $matches;
    } 
    //generate a regex pattern for the given url takes string url returns string
    private function generatePattern($url){
        $pattern = '#^';
        // :text ([a-zA-Z0-9-]+)
        // :id (\d+)

        $pattern .= str_replace([':text', ':id'], ['([a-zA-Z0-9-]+)', '(\d+)'], $url);
        $pattern .= '$#';
        return $pattern;
    }

    //get proper action takes in string $action returns string
    private function getAction($action){
        $action = str_replace('/', '\\', $action);
        return strpos($action, '@') !== false ? $action : $action . '@index';
    }
}


Solution 1:[1]

The call getProperRoute() is returning an array of 2 elements and this is why the "$arguements" is NULL.

You can either change the call to:

public function action ($controller, $method, array $arguements = []){ 
    $object = $this->controller($controller);
    return call_user_func([$object, $method], $arguements);
}

Or check what is the return of the getProperRoute Method

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Thomas Goik