Обновить
16K+
53
Alex Gusev@flancer

Я кодирую, потому что я кодирую…

4,1
Рейтинг
99
Подписчики
Отправить сообщение
В его создании DI-фреймворком, "если конструктор недоступен".
Прошел по ссылке на оригинальную статью. Насколько я понял в "вопросах-ответах" Матиас считает, что этот подход хорош в самых простых объектах, которые и тестировать-то нет неообходимости. Ну что ж, каждое решение имеет свою область применения.
Меня интересовало, что будет инжектиться в класс, завязанный на класс Time, если его конструктор недоступен:

class DependedClass {

    public function __construct(Time $time) {
        // ...
    }
}

Т.е., данный подход предполагает в таких случаях создавать фабрики, которые будут создавать объекты с использованием их собственных статических фабричных методов, и уже эти фабрики инжектить в зависящие от объектов классы (или, как в случае с Symfony, указывать в настройках DI, что для создания экземпляров Time нужно использовать "factory: [TimeFactory, create]"):

class TimeFactory {
    public function create() {
        $result = Time::fromValues(0, 0);
        return $result;
    }
}

class DependedClass {

    public function __construct(TimeFactory $factory) {
        // ...
    }
}

Вполне возможно, в этом есть какой-то сакральный смысл, но я бы все-таки конструктор не прятал. Ну или очень сильно ограничил бы применение "именованных конструкторов" — все-таки статика к тестам совсем не friendly. Вообщем, мне эти "именованные конструкторы" как-то не совсем по душе. Но смотрятся красиво, не отрицаю.
А как этот подход уживается с Dependency Injection (Zend, Symfony, ...)?
Массивна уж очень. Гибкость достигается за счет сложности. Плюс высокий порог вхождения, неочевидность некоторых решений, размазывание функционала между уровнями (например, формирование в PHP-скриптах JS-кода для фронта). Все это и приводит к тому, что решение нельзя назвать "изящным". Гибким, мощным — можно. Изящным — я бы поостерегся. Хотя вторая версия, на мой взгляд, более "прямая" (а может я уже привык думать "Magento style"). Это я как разработчик говорю, а не как конечный пользователь.
Не плохое. "Все есть яд, и все есть лекарство. Зависит от дозы." (с) Парацельс

Просто у angular'а своя ниша, и ее границы достаточно хорошо видны. Инвестировать свое время в разработку прототипа на angular'е, если твое web-приложение строится на чем-то другом — не самое оптимальное решение, IMHO.
Замечательная статья! Как "Матрица" или "Шестое чувство"! Интригует, зовет узнать, как получить все эти увлекательные плюшки и незадорого, а ближе к концу раз — и angular. Ощущение, как доской по голове дали. Зато сразу отрезвление наступило и морок пропал. Да, "серебряной пули" не существует, каждое решение имеет свои границы применимости, angular ничуть не хуже ember/knockout/backbone/smartclient, а твои проекты — это те проекты, в которых прототипирование такой ценой не нужно. Нет, разумеется, есть такие по настоящему крупные проекты, в которых построение прототипа на angular'е дает все эти бонусы и плавно перетекает в production (особенно, если production тоже на angular'е), но вот для твоих задач (разработка модулей для Magento) и бумаги хватит (или Enterprise Architect'а, если нужно красиво). В любом случае, написано здорово, а то, что цена высока — так никто не говорил, что это для всех.
Пожалуйста. На хабре не любят неинформативные комменты — такова специфика ресурса. Поэтому и минусят.
Нет. Я думаю, что в сложных вопросах бывает более одного правильного решения, оптимальность каждого из которых зависит от критериев оценки.
Спасибо за код. Я сравниваю свой код из статьи:

public function __construct(
    \Psr\Log\LoggerInterface $logger,
    \Zend_Db_Adapter_Pdo_Abstract $dba,
    ISomeService $service,
    ...
) {...}

и ваш пример:

public function __construct(MyServiceInterface $service, LoggerInterface $logger) {
     $this->service = $service;
     $this->logger = $logger;
} {...}

и, честно сказать, не нахожу особой разницы. С точки зрения темы, освещаемой в статье, ее нет вообще.

Я хотел для примера воткнуть хоть какие-то более-менее правдоподобные зависимости в конструктор, чтобы не писать "ISomeService1", ..., "ISomeService4", а получилось, что я нарушил "принцип единственной ответственности". В результате дискуссия ушла в сторону правомерности использования логирования для трассировки выполнения бизнес-операций.

Спасибо, что осветили свою точку зрения на этот вопрос (про логирование) — мне, по крайне мере, было очень интересно.
Можно и штаны через голову надеть, при должном усердии.
То, что Magento 1 из до'composer'овской эпохи.
Чем интерфейс "логгер-декоратора" отличается от PSR3?

interface LoggerInterface
{
    public function emergency($message, array $context = array());
    public function alert($message, array $context = array());
    public function critical($message, array $context = array());
    public function error($message, array $context = array());
    public function warning($message, array $context = array());
    public function notice($message, array $context = array());
    public function info($message, array $context = array());
    public function debug($message, array $context = array());
    public function log($level, $message, array $context = array());
}

Можете привести для примера 2-3 публичных метода "логгер-декоратора"?
но на сколько я понял из ваших слов, вы пытались выбрать между двумя фреймворками для выбора между двумя пакетами

из моих слов:

У Magento 1 гораздо большее кол-во расширений.

Здесь "расширение" не равно "пакет". В одном случае в конечной системе требуется поддержка helpdesk'а, в другом — мультисклад. Вот у Magento 1 гораздо больше таких вот расширений, чем у второй версии. Никто не знает, будут ли эти расширения портированы на М2 через полгода. Если будут — завернемся на вторую версию, если нет — на первую.
Никогда еще не сталкивался с проектом, в котором сначала бы реализовывалась бизнес-логика, а затем подбирался фрейворк.

к этому.
Так и есть, composer вытягивает это дело :)

Как же тогда автор предлагает писать бизнес-логику, если заранее не известно будет в вашем фреймворке использоваться DI или не будет

Я создавал у себя в приложении обертку, если фреймворк предоставляет DI — использую его, нет — использую Zend'овский. Ну а классы с бизнес-логикой вообще не интересует, кто и как в них заинжектил нужные зависимости.
что именно? Письма слать он может?

Да.

Меня, если честно, ваши вопросы ставят в тупик. Эти функции, как и запись в БД, и ротация лог-файлов, и изменение формата вывода сообщений без изменения кода приложения, на уровне конфигурационных файлов давным-давно не являются экзотикой в фреймворках логирования.

В Java этого добра поболее — java.util.logging, log4j, slfj4, в PHP я использовал только log4php и собственно Monolog (PSR3 имплементацию). Я не вижу смысла проектировать логгеры — они уже есть. Остается их только использовать там, где нужно. А в сложных системах, да еще и в случае "гибкой архитектуры", их нужно использовать чуть менее, чем везде (слегка утрирую, но для сервисов, реализующих бизнес-логику — везде).

Если вы же и поддерживаете те приложения, архитектором которых вы являетесь, у вас не может быть другого мнения на этот счет.
Для начала я бы использовал готовый PSR3-фреймворк — Monolog. Затем, убедившись, что он не конфигурируется через внешние файлы, я бы обернул его в monolog-cascade. После чего я имел бы возможность через конфигурационный файл влиять на все логи приложения с возможностью их вывода в "никуда"/файл/базу/syslog/email/… С использованием процессора IntrospectionProcessor (подключаемого через конфиг, когда мне нужно) я имел бы возможность расширять сообщения до такого формата:
[YYYY-MM-DD HH:MM:SS] main.DEBUG: MESSAGE_HERE. {"file":"/.../Main_Test.php","line":75,"class":"...\\Main_IntegrationTest","function":"test_main"}

Чего мне уже бы хватило для нахождения в лог-файле (я в основном использую их, но можно и в БД лить) сообщения с конкретной строки конкретного метода конкретного класса (вне зависимости от его уровня логирования).

Если же мне и этого мало, а мне нужно по конкретному сообщению создавать, например, таск support'у в JIRA, то я могу написать свой handler/processor/formatter и подключить его через конфиг-файл без изменения кода сервиса:

public function __construct(
    \Psr\Log\LoggerInterface $logger,
    ...
) {
    $this->_logger = $logger;
    ...
}

public function operation($request) {
    $this->_logger->info("Operation is called.");
    ...
}

Если нужна еще большая гибкость, то да — это решение не подходит, и нужно применять что-то другое. Возможно даже EventDispatcher.
для конкретного лог-сообщения вам нужно поменять уровень с debug на warning.

это гораздо более гибкий вариант поведения

Т.е., в более гибком варианте поведения мне нужно будет изменить код слушателя, я правильно понял?
Если предполагается, что в сервисе могут возникнуть различные варианты обработки лог-сообщений (помимо стандартного уровня — debug, info, ...), то нужно маркировать подобные сообщения на этапе девелопмента (см. второй параметр $context в LoggerInterface). После чего на уровне конфигурирования можно перенаправлять ваши сообщения куда хотите.

Если вы сначала написали код, а потом решили, что он должен работать по-другому, то да — код нужно будет менять.

Информация

В рейтинге
1 418-й
Откуда
Рига, Латвия, Латвия
Дата рождения
Зарегистрирован
Активность

Специализация

Фулстек разработчик
Ведущий
От 3 000 €
JavaScript
HTML
CSS
Node.js
Vue.js
Веб-разработка
Progressive Web Apps
PostgreSQL
MySQL
GitHub