Rozbudowa kontrolera. Użyjemy sztuczki zwanej late static binding aby móc lepiej obsługiwać nieistniejące metody kontrolera. Do dzieła.

Ostatnim razem dodaliśmy sobie coś takiego:

//(...)
$router->add("/products", ["controller" => "product", "action" => "list123"]);
$router->add("/product/list", ["controller" => "product", "action" => "list"]);
//(...)

Oczywiście kontroler Product nie posiada metody list123. Ona była po to, aby pokazać, że metoda __call() działa:

<?php 
abstract class Controller {
    public function __call($name, $arguments)
    {
        die("404 NOT FOUND");
    }
}

Co jednak, gdyby nie tworzyć takiej metody (list123), ale utworzyć plik product_list123.php?

<?php
echo "hello from product_list123.php!";

Można by taki plik dołączyć. Pytanie, jak to zrobić. Potrzebujemy nazwę klasy i nazwę metody:

<?php 
abstract class Controller {
    public function __call($name, $arguments)
    {
        echo __CLASS__ . " " . $name;
        die("");
    }
}
//Controller list123

Tu pojawia się problem – o ile nazwa metody wyświetla się dobrze, o tyle __CLASS__ daje nam „Controller” zamiast konkretną w danym przypadku klasę pochodną (Product).

Można to obejść poprzez tzw. late static binding:

<?php 
abstract class Controller {
    public function __call($name, $arguments)
    {
        echo get_class(new static) . " " . $name;
        die("");
    }
}
//Product list123

Teraz, skoro wyświetla się poprawnie, możemy sprawdzić, czy taki plik „product_list123.php” istnieje i go dołączyć. Jeżeli nie – błąd:

<?php 
abstract class Controller {
    public function __call($name, $arguments)
    {
        $cls = strtolower(get_class(new static));
        $action = $name;
        $path = __DIR__ . "/{$cls}_{$action}.php";
        if(file_exists($path)){
            require $path;
        } else {
            die("404 NOT FOUND");
        }
        
    }
}
//hello from product_list123.php!

Działa. Teraz możemy usunąć plik „product_list123.php” – wtedy dostaniemy błąd, czyli też działa, jak należy.