PHP Overloading – metody z różnymi ilościami atrybutów

Dzisiaj napotkałem na mały problem z kompatybilnością metod. W szybki sposób omówimy dlaczego warto używać magicznych metod takich jak np __call.

Klasa Website

<?php

namespace Development\Controller;

/**
 * Class WebsiteAction
 * @package Development\Controller
 */
class WebsiteAction extends Base
{
    /**
     * @param $id
     */
    public function execute($id)
    {
        parent::execute();

        $user = $this->userManager->getByLogin($_SESSION['login']);
        $website = $this->websiteManager->getById($id);

        if ($website->getUserId() == $user->getUserId()) {
            $this->website = $website;
        }

        require __DIR__ . '/../view/website.phtml';
    }
}

Klasa Base:

<?php

namespace Development\Controller;

/**
 * Class Base
 * @package Development\Controller
 */
class Base
{
    /**
     * @var bool
     */
    protected $isLoginRequired = true;

    /**
     * @return bool
     */
    public function isLogged()
    {
        return (isset($_SESSION['login'])) ? true : false;
    }

    /**
     * Check if login is required and user is logged.
     * If login required and not logged in, throw 403.
     */
    public function execute()
    {
        if ($this->isLoginRequired && !$this->isLogged()) {
            include __DIR__ . '/../view/login.phtml';
            exit;
        }
    }
}

W tym przypadku tylko klasa Website dla metody execute przyjmuje atrybut $id. Problem w tym że PHP wyświetli warning:

Warning: Declaration of Development\Controller\WebsiteAction::execute($id) should be compatible with Development\Controller\Base::execute()

 

Mamy problem, to szukamy rozwiązania. Zaczynam od stackoverflow i szybko znajdujemy ten temat: Declaration of Methods should be Compatible with Parent Methods in PHP.

Według sugestii z stackoverflow problem próbujemy rozwiązać przy pomocy funkcji func_get_args jednakże w tym przypadku to nie zadziałało.

Chwila przerwy na herbatę i sprawdzamy kolejny pomysł z głowy, tym razem trafiamy na:   Same named function with multiple arguments in PHP.

Skutecznie pomogła tutaj magiczna funkcja __call

    /**
     * Check if login is required and user is logged.
     * If login required and not logged in, throw 403.
     */
    public function executeMethod()
    {
        if ($this->isLoginRequired && !$this->isLogged()) {
            include __DIR__ . '/../view/login.phtml';
            exit;
        }
    }

    /**
     * @param $name
     * @param $arguments
     */
    public function __call($name, $arguments)
    {
        if ('execute' === $name) {
            $this->executeMethod();
        }
    }

Po zastosowaniu tego rozwiązania, nasze metody execute mogą przyjmować dowolną ilość argumentów, a PHP nie będzie ostrzegało nas o błędach.