Как правильно работать с фасадами?

CoolKid

Новичок
Допустим есть интерфейс
PHP:
interface IFacade {

    public static function inst();
}

и абстрактный класс

PHP:
abstract class AFacade implements IFacade {

    private function __construct() {}
    private function __clone() {}
    private function __sleep() {}
    private function __wakeup() {}

    public static function __callStatic($method_name, $arguments)
    {
        if(is_null(static::$inst)) static::inst();

        if(method_exists(static::$inst, $method_name))
        {
            return call_user_func_array(array(static::$inst, $method_name), $arguments);
        }
        else
        {
            throw new Exception('Method '.$method_name.' not found in class '.get_class(static::$inst));
        }
    }
}

также есть класс FLoader

PHP:
class FLoader {

    protected $args=array();
    protected $loaded_classes=array();

    public function __construct()
    {
        $args=func_get_args();

        if(Lib::chkArr($args)) {
            $this->args=$args[0];
            $this->lang=$this->args[0];
        }
    }

    public function load($class_name,$parameters=array())
    {
        if(!Lib::chkArrKey($class_name,$this->loaded_classes)){

            $this->loaded_classes[$class_name] = $this->getNew($class_name,$parameters);
        }

        return $this->loaded_classes[$class_name];
    }

    public function getNew($class_name,$parameters=array())
    {
        if(class_exists($class_name)) {
            return new $class_name($parameters);
        } else {
            throw new FException(Lang::getMessage('system.core.class_not_found',array($class_name)));
        }

    }

}

и фасад Loader

PHP:
final class Loader extends AFacade
{
    protected static $inst=null;

    public static function inst()
    {
        if(is_null(static::$inst))
        {
            if(func_num_args() > 0)
            {
                static::$inst=new FLoader(func_get_args());
            }
            else
            {
                static::$inst=new FLoader();
            }
        }
    }
}
Никаких проблем с использованием фасада нет. Например, Loader::load('myclass');
Но с автокомлитом в ПХПШторме беда, пишет что метод load не найден в классе Loader, что в принципе понятно.
В чем ошибка? В неправильной работе с фасадом? или нужно предпринять какие-то действия, чтобы ПХПШторм правильно автокомплитил код?
 

AmdY

Пью пиво
Команда форума
Никак, дело в том, что фасад как раз позволяет менять набор методов, потому их невозможно определить не ран тайм. Можно использовать костыль, рефлекшином обходить зафасаженный класс и генерировать прокси класс чисто для ide, как это делает https://github.com/barryvdh/laravel-ide-helper
 

keltanas

marty cats
CoolKid, Дык дело в том, что
PHP:
<? public static function __callStatic($method_name, $arguments)
как бы противоречит интерфейсу IFacade.
Определи в интерфейсе все методы, которыми должен обладать фасад и реализуй их.
А то метод в интерфейсе не определен, а ты его используешь? Что за бред?
 
  • Like
Реакции: WMix

keltanas

marty cats
Что такое интерфейс? Разве это не декларация всех публичных методов, доступных потомкам этого интерфейса?
Я нигде не писал, что нужно магический метод в интерфейс пихать. Я писал о том, что нужно декларировать метод, который будет использоваться всеми объектами, которые принимают этот интерфейс.
В твоем случае это load(). Деларируй его в интерфейсе, реализуй в конкретном классе.
Все будет четко и понятно. Как ide, так и другим разработчикам, которые будут поддерживать этот код.

PS: Нафига такой фасад, ничего не украшает, а повторяет интерфейс украшаемого класса? Это не фасад, это какое-то разочарование.
 
Последнее редактирование:

CoolKid

Новичок
Вот так и знал, что до лоадера докопаются, надо было на ФуБарах показывать...

Давайте зайдем с другой стороны, возможно у меня ошибка выбора шаблона проектирования.

Итак, есть много классов, которые обеспечивают основной функционал системы: FRouter, FRegistry, FInput, FOutput, FLoader, FSession итд. По названиям я думаю понятно, что именно эти классы делают.
Весь функционал содержатся именно в них.
Как же с ними правильно работать в рантайме?

Ну например можно так:
PHP:
$router=new Router;
$router->addRoute('/^\/index.html$/',array('Controller_index','action_index'));
Но понятно, что это невозможно, т.к. нужен один экземпляр на всю систему. Неприемлемо.

Можно сделать их всех синглтонами и радоваться, но каждый, кто думает, что он что-то там понимает в ООП и PHP, начнёт плеваться слюной и доказывать мне, что я быдлокодер. Неприемлемо.

Можно сделать общий глобальный объект и работать с ним
PHP:
$router->HuYuii::app()->addRoute('/^\/index.html$/',array('Controller_index','action_index'));
Слишком длинная запись, лично мне режет глаз. Неприемлемо для меня.

А можно сделать как сделал я: применить Фасад-синглтон к каждому классу, т.е. на каждый FClassName у меня есть класс ClassName, который его оборачивает и позволяет работать с ним конструкцией
PHP:
ClassName::method();
Если эта задача имеет другие пути решения, более изящные и правильные, с радостью их выслушаю.
 
Последнее редактирование:

CoolKid

Новичок
ага, супер, и на каждый новый метод в классе FRouter создавать метод в Router?
нет, спасибо
 

keltanas

marty cats
Мое мнение однозначно - http://symfony.com/doc/current/book/service_container.html
Хотя и не претендует на звание единственно верного. Т.к. многим это кажется слишком сложным.
Тем не менее контейнер заставляет явно декларировать зависимости, что в итоге делает код более чистым, более слабосвязанным и более простым для поддержки.
ага, супер, и на каждый новый метод в классе FRouter создавать метод в Router?
нет, спасибо
Ты тоже оправдываешь свой гавнокод свой ленью?... Все ясно

Загружай маршруты из конфига или датабазы. Никто не заставляет для каждого маршрута отдельный метод создавать. Это же не контроллер.
 

CoolKid

Новичок
Мое мнение однозначно - http://symfony.com/doc/current/book/service_container.html
Хотя и не претендует на звание единственно верного. Т.к. многим это кажется слишком сложным.
Тем не менее контейнер заставляет явно декларировать зависимости, что в итоге делает код более чистым, более слабосвязанным и более простым для поддержки.
Я знаком с концепцией сервис-контейнеров в Симфони. Мне она импонирует, но я не хочу применять её для решения этой задачи.
Излишнее стремление к универсальности и абстракция на абстракции не есть гуд, хотя эта тема для холиваров.

Ты тоже оправдываешь свой гавнокод свой ленью?... Все ясно
А кто сказал, что у меня говнокод и что я что-то оправдываю?
 

CoolKid

Новичок
Загружай маршруты из конфига или датабазы. Никто не заставляет для каждого маршрута отдельный метод создавать. Это же не контроллер.
Я разве спросил как мне работать с маршрутами? Или где их хранить? Или как лучше написать класс роутинга?
У меня маршруты грузятся и из конфига и из базы, метод нужен для динамического рантайм создания маршрутов из бандлов или снипетов.

Господа, я уже понял, что я говнобыдлокодер, и лишний раз окунать меня в дерьмо смысла не имеет.
По теме, пожалуйста.
 

keltanas

marty cats
Можно сделать их всех синглтонами и радоваться, но каждый, кто думает, что он что-то там понимает в ООП и PHP, начнёт плеваться слюной и доказывать мне, что я быдлокодер. Неприемлемо
Вот как бы в этом и проблема. Ты боишься, что кто-то будет тебе что-то доказывать, а не того, что у тебя в коде будет слипшаяся лапша.
Опастность синглтонов, что ты никогда не будешь знать, какой код от них зависит. Поэтому и необходимо явно внедрять зависимости. Так начнешь стремиться к SOLID и DRY.
метод нужен для динамического рантайм создания маршрутов из бандлов или снипетов
а ты уверен, что это нужно?
ответь себе на вопрос, где нужен этот метод? а потом уже думай, как его реализовать, а не наоборот
 

Вурдалак

Продвинутый новичок
Вообще может от языка зависит, у меня английский.

UPD: ага, поставь английский, не будет такого.
 
Сверху