Pull to refresh

Comments 227

Я тоже недавно пытаясь разобраться в Yii2 плюнул на это, и написал себе небольшой MVC с нуля.

А еще ранее, когда только вышел ZF, произошло то же самое, но где тот первый движок — я уже и не помню :D

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

Так что мысленно поддерживаю вашу инициативу!

//И да, всегда с трепетным уважением смотрю на людей, сумевших разобраться в Symfony например. У них наверное какой-то особенно огромный мозг, или еще чего такое в этом же духе :)
А когда мастеришь только для себя, то постоянно приходится через несколько лет писать одно и то же заново.

Откройте для себя Github ))

Кстати, в чём-то я с вами согласен. Недовольство именно Yii, который пришлось несколько раз использовать, стало одним из поводов делать что-то своё. Мне просто стало интересно — сможем ли мы с ребятами сделать что-то вроде Yii 3, не таща за собой его фатальные архитектурные ошибки?

Оказалось, что смогли :)
Оказалось, что смогли :)

Пруфы будут?)
А как же. Статье к десятой. Имейте терпение!
Мне кажется, что без пруфов до десятой статьи вряд ли кто-то дочитает.
Код открыт. Какие еще пруфы прямо сейчас вы хотели бы получить?
Вам же уже писали: пруфы применения в сравнении с другими фреймворками, где ясно видно, что ваше решение лучше.
Тот код, который открыт — антипруф. И ниже есть немало аргументов почему это так.
Я услышал ваше мнение, спасибо.
Оказалось, что смогли :)

Тут больше людей интересует каков был алгоритм. Такой:


  • Yii нам не подходит
  • Пишем свое

или такой


  • Yii нам не подходит
  • Ресерчим существующие решения
  • пробуем на парочке понравившихся с идеологической точки зрения написать что-то свое
  • ничего не подходит, попробуем хотя бы из отдельных компонентов запилить
  • не, все грустно по таким-то причинам
  • Пишем свое

Если все происходило по первому сценарию — в этом нет пользы. Если по второму — всех интересуют причины.

«Недовольство именно Yii, который пришлось несколько раз использовать, стало одним из поводов делать что-то своё.»
Допустим, я выбираю фреймворк, на котором реализовать проект. В чем преимущества Runn Me перед тем же Yii2?
Сложно сейчас сформулировать преимущества, когда фреймворк еще в самой ранней стадии сборки. Я планировал раскрывать этот вопрос постепенно, по мере выхода статей и подготовки кода к публикации.

Если кратко, то:
— БОльшая архитектурная стройность, например у нас точно не будет никогда $this->breadcrumbs в контроллерах (!)
— Возможность замены любой части, любого компонента на другой, имеющий аналогичный интерфейс. Например вы можете целиком заменить Renderer с нативного на другой, на базе Twig. Насколько я помню, в Yii это крайне сложно. Например конфиг можно сохранять в файл, в базу или в кэш, просто подставив нужную зависимость. Даже класс приложения (контейнера служб) можно вполне заменить на свой.
— Нет тяжести поддержки старых версий, сразу ориентируемся на 7.1, поэтому нет таких вещей, как «поведения», которые в общем-то в современном PHP не нужны
— Мы сразу закладываем возможность работать с несколькими БД, включая даже возможность строить в рамках ORM relations (разумеется lazy load) между разными базами данных

ну и так далее… отличий будет очень много, я сейчас перечислил лишь несколько первых, пришедших на ум

Следите за публикациями!
не будет $this->breadcrumbs в контроллерах (!)

А хде?
Разумеется в шаблонах :)

Зачем контроллеру вообще что-то знать о том, как будет отдан ответ пользователю? Контроллер готовит данные, представление — форматирует.
Контроллер готовит данные

Так контроллер будет готовить breadcrumbs или нет? :)
Это вам решать в конечном счете. Но я бы не рекомендовал.
UFO just landed and posted this here
В шаблонах делать запросы к БД для получения всех родителей?
Дичь. :)
Не делайте. Зачем это вам?
Если модель является частью «дерева», то соответствующий метод у нее наверняка есть. А уж как он работает — делает один запрос или много — какая вам разница?

В шаблонах вы делаете вывод UI компонента который будет запрашивать модель самостоятельно а уже запросы в базу будут инкапсулированы на уровне модели.

Контроллер готовит данные, представление — форматирует.

Почему же его тогда называют "контроллер" а не "форматтер" или "презентер"?

Кого именно?
Вы спрашиваете, почему «контроллер называют не форматтер или презентер»? Ну наверное потому, что контроллер ничего не форматирует и не показывает ))

Не проснулся с утра, кусок фразы пропустил. В моем варианте выходило "контроллер форматирует". Шэйм он ми.

поэтому нет таких вещей, как «поведения», которые в общем-то в современном PHP не нужны

Как вы заменяете такую конструкцию?


[
        'class' => TimestampBehavior::className(),
        'attributes' => [
            ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
            ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
        ],
        'value' => function () { return date('Y-m-d H:i:s'); },
]
Никак. Вам нужно срочно убрать это из ORM либо в триггер, либо, что лучше, в конкретный компонент бизнес-процесса.

Причем здесь ORM? Это же просто пример. Поведениям можно задавать параметры, в отличие от трейтов, и это удобно. С трейтами можно сделать что-то похожее, но часть инициализации будет в конструкторе, и надо следить, чтобы конфликтов названий не было. С поведениями проще и нагляднее.

Я отвечу вам подробно с примерами в одной из следующих частей. Если кратко: нет, поведений не будет. Как не будет вообще декларативного подхода и «автоматики». Это одно из самых неприятных впечатлений от Yii.

Явное лучше неявного. Код лучше массивов параметров.
Явное лучше неявного. Код лучше массивов параметров.


Полностью согласен. Думаю в 10 грехов программирования, если их собрать, одним из первых будет конфигурирование вместо программирования. В этот грех впадают почти все

Думаю, через год-другой в него окунуться с головой вообще все, учитывая что происходит у нас на тему DI-контейнеров.

Я имел в виду в широком смысле, когда программирование заменяется на сложное конфигурирование — примеров тому тьма тмущая.

Про DI — я вот только что написал свой собственный DI (просмотрел кучу всяких либ — везде перегруженное гуано, ничто не устроило). Ну да к нему конфиг в виде карты классов, конфиг простой и понятный, нет головоломных DisabledOption = false;
UFO just landed and posted this here
Кратко про контейнер симфони:

1. использование аннотаций в рантайме — это чистое зло и никогда их использовать не буду. Что им мешает сделать генератор классов из аннотаций?
2. 769Кб папка dependency-injection — это куда и зачем? Мне места на диске не жалко, мне жалко мусор, который за собой придется таскать. Сколько файлов подгружает при пустом контенйере? Писать сложно и непонятно я умею и этогоне хотел бы от других
3. Dumper, Compiler, Extension, Loader — им действительно место в компоненте контейнера?
4. безумное колво мутных интерфейсов для одного компонента, мне нужен только 1!!! интерфейс.

В топку такие компоненты

Вы не разобрались.


Что им мешает сделать генератор классов из аннотаций

Ничего не мешает. В рантайме будет один класс, в котором явно все прописано.

UFO just landed and posted this here
использование аннотаций в рантайме — это чистое зло и никогда их использовать не буду. Что им мешает сделать генератор классов из аннотаций?

А где там аннотации в рантайме?


769Кб папка dependency-injection — это куда и зачем?

ну откройте и посмотрите. 420 килобайт тестов (можно иногда подсматривать как пример), куча лоадеров из разных форматов в котором вам приятнее держать параметры и дефинишены сервисов, средства отладки (в том числе возможность дамнуть весь граф зависимостей в виде dot файлика). Ну и конечно же кодогенерация, компиляция контейнера и т.д. Что-то вроде возможности проверять зависимости в компайл тайм.


Сколько файлов подгружает при пустом контенйере?

  1. это не столь важно, есть же opcache
  2. в продакшене вы захотите использовать скомпилированный контейнер. На сегодняшний день симфоневый контейнер один из самых быстрых. Тогда в принципе количество подключаемых файлов будет сводиться к 3-4.

  1. Dumper, Compiler, Extension, Loader — им действительно место в компоненте контейнера?


  • Compiler — это то что делает контейнер быстрым и безопасным. А так же позволяет делать многие приятные вещи явно.
  • Dumper — это штуки которые нужны для экспорта контейнера в какой-либо формат, в основном для удобной отладки и разного рода средств автокомплита.
  • Extension — это что-то типа ServiceProvider-ов. Простой способ быстро подключить ваши компоненты а не лепить один гигантский конфиг.
  • Loader — ну надо же откуда-то загружать дефинишены сервисов.

безумное колво мутных интерфейсов для одного компонента, мне нужен только 1!!! интерфейс.

он у вас есть — ContainerInterface. Вам по сути больше ничего не нужно.

Да, действительно, я не стал разбираться симфони, посмотрю еще раз. Ведь такая штука: бегло просматриваю базовые классы/интерфейсы, если мне не нравится стиль кодирования, вижу избыточнное количество методов с неочевидным назначением и т.д. Как правило отвергаю такую библиотеку.
Да, конечно, все из топа выдачи гугла, у всех разное качество и к каждому я находил претензии. Больше всех мне понравился компонент di из codeception
компонент di из codeception

Вы про это? Это не компонент, это просто надстройка для внутренних нужд Codeception. Он лишен основной фичи — нормальной декларации зависимостей, фабрик, возможности прокидывать параметры.

Модуль (термин модуль — устроит вместо компонент?) из codeception я привел в пример того, что можно сделать автоматическую иньекцию малыми средствами, без зависимостей от других модулей. То, что вы назвали (чего нет) должны быть еще каждом своем одном модулле. Все. Если сверх того — это высокоуровневый говнокод.
сделать автоматическую иньекцию малыми средствами

Вот вам пример. Как вы организуете малыми средствами декорацию + автосвязывание? Или как вы организуете локальный бингдинг в пределах модуля.


Ну то есть оно и понятно что простые вещи можно делать просто. Более того, есть же pimple который хоть и не умеет автосвязывания, его можно допилить таким же стилем. Но суть компонентов типа auro.di или symfony/di — решить 95% юзкейсов возникающих в работе с контейнером зависимостей и предоставить возможность расширить поведение для решения остальных 5%.

Просто некоторые действуют по принципу «мне это не надо, значит это всё оверхед и куча мёртвого кода на много мегабайт» или «оно всё тормозит, а значит не нужно!!11». При этом пишут свои кривые поделки и считают себя дико умными. Соответственно либо не сталкиваются с задачами, где необходима «вся мощь», либо вообще не подозревают, что так можно, т.е. просто не в курсе, что такое DI, контейнеры, вот это всё...

При этом пишут свои кривые поделки и считают себя дико умными.

А вот это уже не нужно обобщать :)

Очевидно, что вы — это http3. О ваших взглядах все уже в курсе)

почему же, если брать в среднем то как раз таки про кривые поделки и идет речь. Я бы даже сказал подавляющее большинство.

Можете, пожалуйста, пояснить, что значит?
программирование заменяется на сложное конфигурирование

Буду очень благодарен, если можете привести простой пример кодом.

Это когда вместо нескольких строк кода десятки строк XML. Погуглите по запросу code over configuration. Очень больная тема была во времена популярности grunt-ов всяких.


Как пример — опять же настройка пайплайна сборки билдов, сборки фронтэнда (grunt vs gulp, это сейчас вэбпаки всякие), например в assetic (интересно кто-то еще им пользуется?).


С DI контейнерами так же есть нюансы. Описывать зависимости в yaml или xml крайне неудобно.

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

— callback
— event
— перекрытие в наследнике метода
— возможность запросить и получить список не из жестко привязанного источника

Сами же можете придумать, как разрулить
Я могу привести пример, если позволите.

Плохо:
$rules = [
  "deadline" => "required|numeric|after_timestamp:".$date
];


Хорошо:
if ( empty($this->deadline) ) {
  yield new Exception('Empty column "deadline"');
}
if ( (new DateTime($this->deadline)) < (new DateTime($date)) ) {
  yield new Exception('Invalid column "deadline"');
}
return true;


Код условный, писал на калькуляторе.

«Плохо» смахивает на валидацию в Laravel)

Она и есть.
Ровно то, против чего я всегда выступал — использование конфигов и специфичных DSL вместо кода.

Пишите код, коллеги.
  1. Второй код вполне может выполняться на основе первого.
  2. Копипастить второй код в разные функции валидации плохо. Значит надо как-то обозначать, какие валидации из всех возможных нужны в этом объекте.
UFO just landed and posted this here

Правила валидации можно вынести в отдельный класс и реиспользовать столько сколько нужно. Такие валидаторы можно группировать из низкоуровневых правил в логические группы. Для этого очень хорошо подходит шаблон проектирования Спецификация.

Кто вам сказал про копи-паст? Напишите свой валидатор, инкапсулируйте в него все правила валидации и используйте. И никакого копи-паста.
Тот случай, когда «плохо» очевидно лучше, чем «хорошо»
Хорошо:

плохо потому что не скейлится. Нельзя делать композицию таких правил. Более того, невалидные данные — не исключительная ситуация. Во всяком случае с точки зрения компонента валидации. Для клиента, людей которые должны использовать ошибки валидации, важно не то что у них что-то не так а важно "что не так".

Более того, невалидные данные — не исключительная ситуация

Слышу это уже не в первый раз. И никогда нет внятного обоснования — почему. Скорее всего вы где-то прочли эту фразу, запомнили и повторяете.

Вы не обратили внимание разве на yield вместо throw перед тем, как повторять эту мантру? Условный валидатор генерирует последовательность ошибок валидации. И лишь вышестоящий код решает — (мульти-)исключение это или нет.

Чтобы ему было проще, мы упаковываем ошибки в подходящий класс, реализующий Throwable. Захочет — бросит первую же ошибку, не захочет — соберет их все в мультиисключение и бросит все сразу, не захочет — обработает любым другим подходящим образом.

Нельзя делать композицию таких правил

Оу, как раз при таком подходе композиция элементарна. Что может быть проще, чем последовательно вызвать два-три-N генераторов?
И никогда нет внятного обоснования — почему.

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


Соответсвенно с точки зрения объекта, который производит валидацию, его задача на самом деле не убедиться что данные валидны, а собрать ошибки. И данные будут считаться валидными только если ошибок нет, но это решение будет принимать уже пользователь валидатора.


К примеру у меня был интересный случай. Есть запрос от пользователя который включает в себя какие-то данные по стоку (грубо говоря остаток на складе). Эти данные формируются на клиенте исходя из последних записанных результатов и того что вводит пользователь.


Собственно приходят данные, я кидаю их в валидатор. Валидатор выдает список ошибок. Если список ошибок пустой — все хорошо, идем дальше. Если нет — проверяю где ошибки. Если это ошибки в данных по стоку и именно определенный тип ошибок, я формирую отдельный вид репортов по этой ситуации и записываю эти данные в базу. Причем для различных комбинаций ошибок нужно формировать различные репорты. И с таким подходом можно было читать код как просто описание бизнес логики.


В этом случае "ошибки" это такие же данные как и все остальные.


Чем же исключения отличаются от "ошибок". Вопервых исключения это внутренний механизм языка. Их нужно использовать если вам важно:


  • обеспечить всплытие ошибок по стэку вызовов
  • сохранить точку где произошла ошибка (стэк трэйс)
  • неявный выход из функции (что есть сайд эффект)

Нам же нужен объект который:


  • хранит информацию о том что не так с данными
  • хранит путь в массиве данных (где именно что-то не так)
  • желательно хранить список таких ошибок с сохранением иерархии. То есть дерево ошибок.

Почему PHP разработчики так любят исключения? Потому что модель выполнения позволяет делать любой трэш и все всеравно будет хорошо. Незахэндленные исключения за них обработают фреймворки или просто дефолтный обработчик ошибок PHP.


Если есть возможность избежать появления сайд эффектов, нужно этой возможностью пользоваться. Это очень сильно уменьшает сложность кода на всех уровнях.


Захочет — бросит первую же ошибку, не захочет — соберет их все в мультиисключение и бросит все сразу

продемонстрируйте.


Оу, как раз при таком подходе композиция элементарна. Что может быть проще, чем последовательно вызвать два-три-N генераторов?

приведите пример как вы будете делать что-то подобное:


use Symfony\Component\Validator\Constraints\{
    NotBlank, Collection, Type, Optional
};
use App\Catalog\Constraints\{AvailableProduct};

$productUpdateRules = new Collection([
   [
       'name' => [new NotBlank(), new Type('string')],
       'quantity' => new AvailableProduct(),
       'description' => new Optional([new NotBlank(), new Type('string')]),
   ]
]);

что-то типа такого. А потом сравним по различным параметрам различные подходы.

продемонстрируйте

См. следующую статью: https://habrahabr.ru/post/328080/

Я уважаю ваше мнение и не буду с вами спорить. Но для себя реализовал другой подход и с удовольствием им пользуюсь.

Попробуйте понять и альтернативную точку зрения. В ней нет ничего ужасного.

Большая часть ваших аргументов основывается на том, что вы зацепились за то, что контейнер для какой-либо ошибки наследуется от класса \Exception, но по большей степени тут суть в том, что это лишь контейнер для ошибки(тип), который просто имеет возможность выбрасываться если того требует ситуация на усмотрение разработчика.
В подходе AlexLeonov (если я его правильно понял) — выброс этих объектов не происходит, а происходит выброс коллекции, которая содержит у себя в айтемах ексепшены. И то, выброс этой коллекции подразумевается в вышестоящем коде (судя по комментариям AlexLeonov ). Для примера throw new ValidationExceptions($this->arrayOfSpecificValidationExceptions).


После этого, я думаю становится понятно, что по итогу и в вашем симфони-вей варианте, и в варианте AlexLeonov (опять же, насколько я его понял) — вы имеете коллекцию, которая обладает всем тем, что вам нужно. (что не так с данными, какими данными, иерархия ошибок и т.д.). И до этого момента в ваших подходах не так много разного.


Ваша коллекция ошибок:


class ConstraintViolationList {
  protected results = [
     'name' => [ConstraintViolation('name is blank'), ConstraintViolation('name is not string')],
     'quantity' => ConstraintViolation('quntity not valid'),
  ];

  ...
};

@AlexLeonov коллекция ошибок:


class ValidationResults extends \Exception {
  protected results = [
     'name' => [BlankValidatorException('name is blank'), TypeValidationException('name is not string')],
     'quantity' => QuantityValidatorException('quntity not valid'),
  ];
  ...
};

(Код просто для наглядного сравнения подходов без погружения в ньансы)


Соответственно суть спора можно свести к главному вопросу как лучше получить эту самую коллекцию после вызова ->validate().


  1. Вы предлагаете возвращать коллекции ошибок из функции ->validate().
  2. @AlexLeonov предлагает выбрасывать эту коллекцию в виде ексепшена.

И в вашем случае, и в случае AlexLeonov я вижу сайд эффекты.
Эксепшен — бесспорно сайд-эффект, но в вашем случае чуть сложнее и субъективно с моей стороны. Метод validate в моём представлении должен быть void и делать только то, что определено в его названии — валидировать (правило наименьшего удивления, на которое вы уже где-то тут ссылались + SRP на уровне функции?:D ). Поэтому для получения ошибок, было бы логичней вызвать отдельную функцию getErrors() : ViolationList или же добавить новую validateAndGetErrors() : ViolationList. Соответственно по закону деметры тогда в интерфейсе валидатора появятся такие функции как hasErrors() : bool, countErrors() : int и т.д.


Вероятно этой же логикой руководствовался AlexLeonov.


Должна ли функция validate просто тихо отрабатывать при возникновении ошибок? Тут я хз) Т.к. вижу аргументы и в том, что бы бросить эксепшен, и в том, что бы тихо отработать) Но больше за то, что бы тихо отработать, а вышестоящий код (который вызывал эту функцию) уже решил, что делать с полученной коллекцией ошибок, если они есть. (отрендерить в контроллере или выбросить на глобальный хендлер) О чём кста упоминал AlexLeonov. (о том, что решение за выброс принимает вышестоящий код, который инициировал валидацию)


К примеру в ларе, при валидация пост реквеста при использовании FormRequest происходит выброс в глобальный хендлер, а потом redirect()->back()->withErrors($errors). Думаю подобный же код встретился бы у вас в контроллере, если валидировать реквест в контроллере. Или вы отдаёте хтмл в ответ на POST после субмита формы?


По итогу. Я не вижу принципиальных различий у вас обоих)

В Питоне с этим переборщили, и используют всякие конвенции для private переменных. Причем в результате этот принцип нарушается, так как конвенции это неявная вещь, которая не прописана в коде. Так что везде нужна мера, и основная мера это удобство и понятность. Потому я и спросил, что предлагается взамен.

Предлагается писать код. Если вы хотите присвоить значение свойству, где-то должно быть написано $obj->prop = 'value'

Я не согласен с мифическим «удобством» в качестве меры качества кода. Код должен быть однозначным, читаемым, понятным, целесообразным, минимально необходимым и так далее. Но удобным? Нет, не думаю.
удобный — делающий что-либо приятным, легким в осуществлении чего-либо; уместный, подходящий для чего-либо

Применительно к коду "что-либо" это его создание и внесение изменений. Никаких мифов тут нет. А то, что вы написали относится к чтению кода. "Удобно читать" действительно не очень понятное словосочетание.

«удобством» в качестве меры качества кода

Когда речь идет о конвенции на уровне языка, это нормально так как все просто знают об этом. Это не какая-то выдумка на уровне фреймворка. Правда тут есть маленький нюанс — этот конвеншн никак не влияет на поведение. Это только для того что бы дать понять разработчику мол "вот эта штука — деталь реализации, а не часть публичного интерфейса".

Пока что у вас в коде магии еще больше чем в Yii. get-, set-, validate-, sanitize- методы, которые объявляются в объекте, а вызываются магически при установке свойства. "Стандартный" класс объектов, который имеет и подсчет количества и сериализацию в JSON и много чего еще. Куча трейтов разной вложенности, которые мешают друг другу методами, которые все идут в результирующий объект. Какая-то магия с debug_backtrace при получении свойства. Как-то слишком много неявной автоматики.

Ваше мнение будет учтено в следующих версиях библиотеки. Спасибо.
Иногда массивы параметров, обрабатываемые стандартным для фреймворка документированным кодом, гораздо лучше, чем 15 вариантов «явного кода», написанного 15ю разными разработчиками, в соответствии с 15ю разными жизненными философиями и стадиями ООП головного мозга.
Касаемо сложных систем, как только вы изобретете найдёте свой DI фреймворк и качественно выделите Composition root системы, не станет ровно никакой разницы, кодом вы инициализируете свои конструкторы или набором конфигурирующих параметров.
DI — это просто один из вариантов композиции компонентов приложения. Фреймворк должен предоставить вам способ это сделать, конечно же. Но я не считаю, что DI — панацея, которая делает ваш код плохим.

Код плохим делает нежелание писать код.
Чорт, читать как «не считаю, что DI — панацея, которая делает код хорошим».

Я буду 10 раз перечитывать комментарий перед отправкой!
Не панацея, но весьма удобный подход.
Код лучше массивов параметров.

Я б даже сказал, месива :)

Код лучше массивов параметров.

Нужно просто понимать, что обобщать, а что не обобщать. :)

Жесть какая) А аргументы будут? У нас же тут обсуждение, разве нет?


Я не предлагаю все трейты заменить на поведения. Но есть моменты, где поведения удобнее. Да, не в последнюю очередь это связано с архитектурой Yii, со всеми ее недостатками. Потому я и спросил, как аналогичный результат будет достигаться с учетом архитектуры этого фреймворка. И да, ответ "будет кодом, покажу потом" меня не устраивает. Потому что кодом можно написать по-разному, и объявление массива это тоже код.

Но есть моменты, где поведения удобнее

«Удобство» в данном конкретном случае не есть критерий качества кода.

ответ «будет кодом, покажу потом» меня не устраивает

Я вам уже неоднократно ответил.

Результат, аналогичный показанному вами поведению, достигается строчкой
$model->updated = date('Y-m-d H:i:s')
где-то в коде соответствующего процесса.

Я не рассматривал какой-то конкретный случай. Удобство создания кода с заданным поведением и внесения в него изменений это один из главных критериев разработки. За исключением каких-то специализированных случаев типа оптимизации по производительности.


где-то в коде соответствующего процесса

Вот меня и интересует, где это "где-то" будет, с учетом методов организации кода и работы с БД, и насколько этим будет проще управлять. И повторю, вопрос касается не только ORM, а вообще добавления любой функциональности, которая отличается только параметрами.

Вот меня и интересует, где это «где-то» будет

В коде бизнес-процесса.
Контроллер принимает запрос (request) и видит параметры окружения, запускает соответствующий процесс или цепочку процессов, собирает ответ (response).
Где-то в одном из ваших бизнес-процессов, Michael. Сложно сказать точнее.

М? Ну так метод behaviors() это тоже часть бизнес-процесса. В чем разница?

Разница в том, что поведение модели не есть часть БП.

А чего это тогда часть? Инфраструктуры? Или стека TCP/IP?
Поведение модели это часть бизнес-логики и бизнес-процессов в этой логике. И вопрос-то не в этом, а в повторном использовании кода. В контроллерах тоже есть повторяющийся код, который можно вынести в трейты или поведение. Но ок, я понял, что примеров пока не будет.

В контроллерах тоже есть повторяющийся код, который можно вынести в трейты или поведение.

Перестаньте выносить повторяющийся код. Дублирование кода — это нормально. Особенно в контроллерах.


Когда мы говорим про DRY многие забывают про Try. Далеко не все дублирование нужно устранять. В целом мотивация этого действа весьма простая — если в коде будут баги и этот код дублируется — то надо править в нескольких местах. Однако с другой стороны, когда речь идет про такие вещи как контроллеры, которые декларируют последовательность действий, очень удобно когда весь флоу прописан последовательно и прочитать его можно без прыжков между файлами. А еще веселее становится после того, как через месяц после устранения дублирования вдруг оказывается что "некоторые штуки то оказывается были просто похожи но не являлись дублированием". И разворачивать всю эту штуку уже не так приятно. Та же история и с "поведениями" для Yii. Они конечно здорово и весело, но при определенном масштабе создают сложности для понимания кода.


Так что перед тем как устранять дублирование такими примитивными механизмами как трейты, следует задуматься:


  • А не вытекла ли у меня логика случайно из какого-то объекта? Может она должна быть где-то инкапсулирована?
  • А не проще ли мне вынести эту логику в какой-то отдельный объект, который будет медиатором между той и этой штукой (например между контроллером и моделью данных, или мидлвари, или еще чего).
  • А как много дублирования? одно и то же в двух местах? не, пока рано что-то с этим делать. Добавлю пометку на будущее а если надо будет править буду уже думать.

Ну вот мы подумали и решили вынести. И код везде одинаковый, за исключением какого-нибудь названия. Кстати, поведение это и есть отдельный объект) Просто композиция нестандартная.


Вы все правильно говорите, это надо различать. И хороший способ это представлять в динамике. Если я изменю тут, там надо будет синхронно менять или нет? Зависит ли это от сторонних условий? А если требования поменяются, все равно надо будет вместе менять?

поведение это и есть отдельный объект) Просто композиция нестандартная.

которая делает код не кохисив в случае имплементации в Yii.


А если требования поменяются, все равно надо будет вместе менять?

И тут нужно учитывать не просто что требования могут поменяться, а просто к кому эти требования относятся. Если у вас есть идентичный функционал но он используется разными ролями, то это разные штуки и не надо их объединять пока это не будет совсем уж очевидно. То есть важно понимать зачем и как ваш код используется.

Результат, аналогичный показанному вами поведению, достигается строчкой
$model->updated = date('Y-m-d H:i:s')
где-то в коде соответствующего процесса.


Ну или в нескольких местах… наверное…
Но есть моменты, где поведения удобнее.

это удобно если ваша цель — запилить прототипчик. В долгосрочной перспективе такое неявное смешение логики (пусть и с делегированием ответственности) приведет к тому, что код перестанет явно выражать что хотел сделать автор по итогу. А это существенно увеличит время вхождения разработчиков в проект, увеличит риски для бизнеса и т.д.

Ага.
И делает фактически невозможной сколько-нибудь осмысленную отладку.

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

Судя по перечню, вы находитесь под впечатлением yii1. Во второй версии хлебные крошки и другая презентационная обвеска к контроллеру отношения не имеют. Также есть возможность заменить все и вся, через DI контейнер и сервис-локатор. Базовый renderer меняется на twig одной строчкой в конфиге. Работа с несколькими БД, релейшены межу разными базами (например между mysql и монгой) уже есть, и с ленивой и с жадной загрузкой, как потребуется. Про поведения стоит понимать, что это, в первую очередь, обработчики событий объекта, связанные общей логикой одних бизнес-процессов, и собранные в один класс, который можно подключить через конфиг. И это трейтами не заменишь.

у нас точно не будет никогда $this->breadcrumbs в контроллерах (!)

В Yii они тоже не в контроллерах, если что...


Например вы можете целиком заменить Renderer с нативного на другой, на базе Twig. Насколько я помню, в Yii это крайне сложно.

Не верно. В Yii это в дизайне с самого начала. Более того, есть официальные реализации-примеры для Twig и Smarty.


— Нет тяжести поддержки старых версий, сразу ориентируемся на 7.1, поэтому нет таких вещей, как «поведения», которые в общем-то в современном PHP не нужны

7.1 никак с поведениями не связан. Альтернатива им — трейты. И то не полная. Есть плюсы и минусы.


Мы сразу закладываем возможность работать с несколькими БД, включая даже возможность строить в рамках ORM relations (разумеется lazy load) между разными базами данных

Есть в Yii и коробки.

UFO just landed and posted this here
Во-первых это chaining и то, что я называю innerCast. Обычный stdClass не умеет выстраивать цепочки свойств на лету и превращать «промежуточные» свойства в объекты этого же класса.

Во-вторых управляемость. В базовом классе Std, например, можно задать список обязательных свойств и, если они будут отсутствовать при создании объекта — возникнет ошибка.

Далее перехват присваивания, валидация и санитация данных, которые вы передаете в свойства. Умный конструктор и умный merge(), которые умеют собирать все ошибки валидации в коллекцию ошибок.

Всё это проще сразу заложить в базовый класс. И потом расширять, при необходимости.

P.S. Можете почитать код тестов, например https://github.com/RunnMe/Core/blob/master/tests/Core/StdTest.php и https://github.com/RunnMe/Core/blob/master/tests/Core/StdGetSetValidateSanitizeTraitTest.php — там многое написано понятнее, чем я рассказываю ))
UFO just landed and posted this here
Фабрики объектов нет. Есть кастинг. Это раз.

Валидации нет. Есть интерфейс для подключения валидаторов. Это два.

Сериалайзер? Где? Вы про реализацию стандартного интерфейса из SPL? Для этого он и нужен, чтобы его реализовать.

Следуя вашей логике и реализацию Countable можно признать нарушением принципа единой ответственности :)
Под chaining вы понимаете fluent interface?


Не совсем. FI легко реализуется методами, которые заканчиваются на return $this;
Я же имею в виду то, что в PHP штатными средствами легко сделать

$arr = [];
$arr['foo']['bar'] = 42;

и это совершенно валидный код, но нельзя сделать:
$obj = new SomeClass;
$obj->foo->bar = 42;

Мы этот недостаток в StdGetSetTrait исправляем. Коряво, но по-другому пока никак. Нужно готовить RFC для внесения в сам язык чего-то вроде нативного JSON, чтобы получить возможность создавать одной строкой объекты любой вложенности.

А чем плох вариант $obj->getBar()->setBaz($value)?


Или же вы за полностью immutable подход? Если да, почему?

Или же вы за полностью immutable подход?

Нет. Не полностью. Я за такой подход там, где он оправдан. Например метод filter() в коллекции просто обязан возвращать новую коллекцию, иначе мы не сможем построить fluent interface.

А чем плох вариант $obj->getBar()->setBaz($value)?

Неплох. И даже был в изначальном варианте Std. Выпилен из текущей версии за лёгкой избыточностью, предложение по новой реализации таких сеттеров сейчас обсуждается.

Кстати, у вас в коде ошибка. Метод getBar() вернет значение свойства bar и дальше цепочка прервётся.

Нет, нет. Ошибки нет. Метод getBar() подразумевается, что вернёт объект, который содержит setBaz().
Это может как $this, так и this->propWithSomeBazSetterInterface


Надеюсь, смог донести до Вас свою мысль.

Я вас услышал. Для меня это ошибка. Ваш код нелогичен, метод $obj->getBar() должен возвращать нечто, что является 'bar' в составе $obj

Поэтому принять такое предложение не считаю возможным.

А что здесь нелогичного? Классическая цепочка вызовов.
$obj имеет свойство bar которое содержит объект со своейством baz и сеттером для него.

$obj имеет свойство bar

Здесь нелогичность. В моем примере — не имеет. Оно создается на лету.

В этом то и проблема что свойство создается на лету.
Классы не для того предназначены.

Вы можете не создавать. Я лишь даю вам такую возможность.
Неплох.

Ну разве что мы нарушили закон Деметры и помохали ручкой инкапсуляции.

$arr['foo']['bar'] = 42;

$obj->foo->bar = 42;

Что люди не делают, лишь бы не использовать массивы. :)
Массивы не могут быть типизированы, к сожалению.
Чтобы по пьяни не передать левую переменную? :)
UFO just landed and posted this here

Во славу type-safety и не такое сделаешь.

Мне очень интересна ваша разработка, бегло просмотрел исходники. Какой стиль форматирования кода у вас? Зачем так много пустых строк? Ну это мелочи. Также почему не используете Psr\Container\ContainerInterface? В PSR мало интерфейсов, чтобы ими пренебрегать. А есть ли интерфейсы, которые вы хотели, чтобы они стали общепринятым стандарттом? Мне вот точно хотелось бы расширить PSR.

Что не увидел: DI, фабрики и как рулить их конфигами. Очень интересно было бы посмотреть ваш подход к этому. Насторожил синглетон в ядре.
Контейнеры будут позже. А синглтона не бойтесь, в нем нет ничего страшного, просто дана эталонная реализация.
public function testDifferentInstances()
    {
        $obj1 = testClass1::instance();
        $obj2 = testClass2::instance(1, -1);
        $this->assertNotSame($obj1, $obj2);
        $this->assertInstanceOf(testClass1::class, $obj1);
        $this->assertInstanceOf(testClass2::class, $obj2);
    }

Как вы тут скромно обошли проверку ->x и ->y, а ведь это самое интересное.
Вообще именно поэтому синглтон и считается анти-паттерном, что вызовы:


$obj1 = testClass1::instance(0, 0);
$obj2 = testClass2::instance(1, -1);
echo $obj2->x;


дадут нам совершенно неожиданный результат.


Мне кажется, что это нужно срочно отрефакторить и сингтон убрать.

ну вот, первый ценный коммент на статью :))
спасибо!

P.S. я действительно тут скромно обошел, думаю, как лучше сделать. но вы, разумеется, правы.
Благодатная идея объекта, состоящего из произвольных свойств, которые можно создавать и удалять «на лету», как элементы в массиве, приходит в голову каждому программисту на PHP.

Зачем? Пожалуйста, объясните зачем вы это делаете? Откуда в PHP эта «мода» делать из объекта массив?
Это наоборот: из массива объект. Мы любим массивы и хотим добавить к ним методы ))

На самом деле применений дальше будет множество.
Мы любим массивы и хотим добавить к ним методы

т.е. сделать то, что и так уже есть в языке — объекты.
ArrayAccess входит в тройку самых ужасных для меня возможнойстей PHP: сразу за магическими __get, __set
и ReflectionProperty::setAccessible().
Код с применением указанных возможностей прекрасный способ усложнить себе и другим разработчикам жизнь.
В таком случае вы просто не любите PHP?
Я такого не говорил. Я говорил только о нескольких возможностях языка.
PHP начиная с версии 5.3 достаточно хорош, а с приходом 7.х еще лучше.
Ну хорошо. А то уж я подумал вдруг ))
начало выглядит неплохо, жду продолжения
UFO just landed and posted this here
UFO just landed and posted this here
чтобы реализовать Value Object который хранит одно число?

Если в этом был единственный ваш вопрос, то ответ «да», именно так. Хранит в неизменном виде, позволяет создавать, валидировать при создании, не позволяет изменять ну и еще ряд полезных на практике возможностей.

А что?
UFO just landed and posted this here
Нет.
Это фактически заглушка, которая никогда не будет использоваться. Кроме как для зеленых тестов.

Если встретите где-то goto — сообщите сразу :)

Впрочем, как учебный пример — прекрасно. Сразу можно разобрать опасности такого подхода и показать на примере php-инъекцию.

P.S. Про библиотеку сериализации будет другая статья.
UFO just landed and posted this here
Отвечаю на заданные вопросы.

Зачем делать класс валидатор с состоянием, вынуждая создавать новый экземпляр на каждую валидацию?

Состояние в данном случае — побочный эффект применения ООП и наследования. Расскажите, как сделать правильнее.

От чего вы пытаетесь абстрагироваться таким образом? От самого PHP?

Не сумел ответить. Ваш вопрос не содержит позитивного или негативного утверждения. Всё равно что спросить «а ваши родители знают, что вы гей?»
Состояние в данном случае — побочный эффект применения ООП и наследования. Расскажите, как сделать правильнее.

не использовать наследование?


В целом решение проблемы — правила валидации отдельно, валидация отдельно. В этом случае можно делать много прикольных вещей в плане композиции правил.

Сразу можно разобрать опасности такого подхода и показать на примере php-инъекцию.

почему в ваших примерах нет ничего о IoC? Это одно из основных чему нужно учить студентов когда речь идет про архитектуру и фреймворки. Я вот студентам вот такую картинку показывал как противопоставление вот такой картине.


Студентов не с php-инъекциями надо учить бороться, а объяснять им силу инкапсуляции и полиморфизма, проблемы связанности и преимущества зацепления… структурное программирование (и немного функциональное).

почему в ваших примерах нет ничего о IoC?

Потому что статья не об этом.
Если встретите где-то goto — сообщите сразу :)

А что с ним не так?
Кто сказал «не так» кроме вас?
Просто сообщите, пожалуйста. Это же очень интересно!
Но через два часа программирования такими «обьектами» они превращаются в ружье и отстреливают фокуснику обе ноги.

В ружье Чехова, которое выстрелит под конец — а именно на боевом сервере))
Если вы приведете мне конкретный пример — буду счастлив.
Это уже данность такая — любую статью про РНР начинать с нескольких абзацев извинений?
Мне показалось, что в праздничный вечер немного лирики не помешает. Вам помешало?
Хорошей лирики много не бывает!
PHP хорош тем, что ему не нужен никакой фреймворк. То, для чего он предназначен, не требует фреймворков, потому что реализуется за день, без всяких ненужных абстракций.
Теперь же php превратился в говнокод завернутый еще и в фреймоворк (который тоже часто состоит из говнокода), что только многократно все усложняет. Если в голове каша, никакой фреймворк не поможет. Поэтому и каждый берется за очередной «фреймворк», понимает что это пипец и… садится делать такой же пипец, только свой, из своей каши.
Зачем все эти абстракции над и так уже хорошо работающими внутренними механизмами PHP?
Самое печальное что теперь во все это верят и работодатели, подбирая людей под фреймворк, потом меняя фреймворк…
Все мое личное имхо, и наблюдение, рад ошибаться
Я думаю, что вы ошибаетесь.

Фреймворк — способ решения стандартных задач стандартным путём. Работодатель стремится свести к нулю как раз время решения стандартных задач, верно полагая, что хороший фреймворк уже всё сделал за разработчиков.

Другое дело, что пока что идеального фреймворка нет. Есть пара-тройка хороших да и только.

А абстракции нужны затем, что так устроен наш, homo sapiens, способ мышления. Анализ, синтез, абстрагирование, обобщение, конкретизация…
Адекватная точка зрения на хабре не приветствуется. :)

Приветствуются адекватные доказательства своей точки зрения. Применительно к вашей точке зрения — код вашего фреймворка и проектов на нем написанных. А вам лень push на github сделать. Или стыдно, что более вероятно. Вот за бездоказательные утверждения сомнительных преимуществ вас и минусуют, как и комментатора выше, а не за саму точку зрения.

Какие преимущества? :)
О чем речь? :)
Благодатная идея объекта, состоящего из произвольных свойств, которые можно создавать и удалять «на лету», как элементы в массиве, приходит в голову каждому программисту на PHP. И каждый второй эту идею реализует.

И что же это, каждый второй не может использовать конструкцию ;$result = (object) $array &
Не совсем ясно, где у вас "&" и что конкретно этот символ обозначает?
Оххх. И вот, опять, кто-то написал Фреймворк с ощущением, что всем не пофигу на него. Есть фреймоврки с большими сообществами, которые, как минимум могут нормально сформулировать свои конкурентные преимущества, сильные и слабые стороны. Фреймворк ради фреймворка это какая-то дичь, как по мне, если это не делалось в учебных целях(да, ваш делался и делается, но зачем каким-то широким массам показывать?). Нет у программиста качества хуже, чем изобретение велосипеда без видимых на то причин. Непонравился Yii2? Ну посмотрите Symfony, Zend, Laravel, Phalcon. НЕТ! ЗАЧЕМ? Будем городить еще кучу велосипедов.
Я уж не говорю о том, что вы НЕ поняли разницу между Value Object и Entity судя по вашему же репозиторию ValueObjects. Особенно позабавило: `$object = $entity->toValueObject();`. Очень странная и неочевидная структура внутри ваших библиотек. Объекты, интерфейсы, исключения, люди, кони, львы! Все смешалось в одном namespace.

Не поймите меня неправильно, я бы, наверное, написал бы куда более мягкий и воодушевляющий комментарий к вашему творению, если бы вы написали, так, мол и так, учебных целей для делаю свой Фреймворк, ищу помощи от сообщества, оцените, пожалуйста! Ну или что-то в таком духе. Но нет! Вы учите людей, заявляете, что это все проверено в «боевых проектах» и вообще все довольно шоколадно. Но я должен констатировать, что использование ваших подходов в крупных проектов приведет к скорому краху, поскольку у вас есть явное недопонимание тех вещей, которые вы пытаетесь использовать, либо внедрить.

Вы говорите о каком-то там архитектурном превосходстве над каким-то из популярных фреймворков, хотя допускаете в своем ядре такие вот вещи:
https://github.com/RunnMe/Core/blob/master/src/Core/Std.php

В общем, вы сам все написали в начале, я просто оставлю этот комментарий здесь и надеюсь в ответ от вас услышать ответ на вопрос: «В чем разница между Entity и ValueObject и почему код, который я привел выше — абсурд?».
Если вы с самого начала вместо бетона используете говно и палки и при этом заявляете, что ваше здание в архитектурном плане лучше, чем Empire State Building — какой реакции от сообщества Вы ждете?

Все-таки, посмотрите на ядра Symfony, Zend, Laravel, Phalcon и как они устроены, а потом ответьте себе на вопрос: «Стоит ли использовать говно и палки для строительства, когда у вас есть бесплатные пеноблоки?». Меня очень смутил тот момент, что вы учите программировать… Где Pull-request? Come Review? Come Discussion? Project roadmap? Contribution guide? Architecture notes? Да банально описание проекта, или хотя бы понятные комментарии в коде?

Еще раз прошу прощения, но не я написал эту статью.
> Come Review? Come Discussion?

Code само собой) Т9…
НЕТ! ЗАЧЕМ?

Это внутренняя потребность творить. Разве вам она не знакома?

вы НЕ поняли разницу между Value Object и Entity

В данной статье мы не обсуждаем библиотеку ValueObjects. Впрочем, если вам хочется — пожалуйста. Но конструктивное обсуждение будет в статье, посвященной именно ей.

если бы вы написали, так, мол и так, учебных целей для делаю свой Фреймворк, ищу помощи от сообщества, оцените, пожалуйста!

Я не ищу помощи. Я буду ей благодарен, но не ищу. Особенно я не ищу помощи от тех, кто пишет «фреймоврки», «Непонравился», «Come Review»

Еще раз прошу прощения

Вам не за что просить прощения. Вы просто высказали своё мнение. Спасибо. Любое мнение ценно.

P.S. Зачем всё время «Фреймворк» с большой буквы? Это имеет какой-то смысл?
P.S. Зачем всё время «Фреймворк» с большой буквы? Это имеет какой-то смысл?


Т9, я сразу-же в ответе написал.

Это внутренняя потребность творить. Разве вам она не знакома?


Внутреннюю потребность творить лучше направить на что-то полезное не одному только Вам, Вы так не считаете?

Я не ищу помощи. Я буду ей благодарен, но не ищу. Особенно я не ищу помощи от тех, кто пишет «фреймоврки», «Непонравился», «Come Review»


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

Я не ищу помощи. Я буду ей благодарен, но не ищу.

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

Я именно так и считаю. Иначе бы не писал это статью.

А какая цель публикации? Чего Вы хотели ей добиться?

Чистое, незамутненное творчество. Чего пытался добиться Малевич, выставляя «Черный квадрат»? Я не знаю, но предполагаю, что однажды творчество превращается в потребность. У вас не так?

То, что я пишу комментарии на Хабре с включенным Т9

Где хоть вы его откопали? У вас реально что-то вроде Siemens S45?

никак не говорит обо мне, как о программисте, не так ли?

Хрен знает. Общее впечатление составляет. Неаккуратненько (с).

больше мне сказать нечего

Хорошо.
Фабиену и Тейлору кто-то точно также говорил :)

А уж что говорили Расмусу — я не могу написать по цензурным соображениям!
Не слушайте никого, делайте что душа просит! :)
Просто не понял зачем. Зачем делать «все массивами» и т.п. Любой фреймворк имеет право на существование. Буду следить за продолжением. :) Надо только еще понять, как это все применить. Надеюсь в следующих сериях картина прояснится.

Просто не понял зачем

Вы не поняли. Не поняли зачем.
Честно — не знаю, что вам ответить. Ну ОК, постарайтесь понять :) Спросите, если что будет непонятно, хорошо?

Постарайтесь объяснить какие именно характеристики фреймворка были вам важны когда вы принимали такие решения. Это всегда интересно.

Ну ОК, постарайтесь понять :)


Так мы тут все это и пытаемся понять, а вы отвечаете только в духе «Захотелось». Ну, ок, но я же не пишу статью на хабре о том, что мне захотелось сегодня съесть борща. Пока что из Ваших же ответов следует, что вы делаете фреймворк ради того, чтобы сделать фреймворк. Понимаете, есть разница между «прыгнуть ради того, чтобы прыгнуть» и «прыгнуть, для того, чтобы запрыгнуть куда-то\перепрыгнуть что-то».
Так вы не задали ни одного вопроса же!
Если бы был вопрос — был бы ответ.
Так вы просто игнорите вопросы) Давайте напомню:

Фреймворк ради фреймворка это какая-то дичь, как по мне, если это не делалось в учебных целях(да, ваш делался и делается, но зачем каким-то широким массам показывать?


Стоит ли использовать говно и палки для строительства, когда у вас есть бесплатные пеноблоки?


Постарайтесь объяснить какие именно характеристики фреймворка были вам важны когда вы принимали такие решения. Это всегда интересно.


Просто не понял зачем. Зачем делать «все массивами» и т.п.


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

Мне так захотелось. Не вижу причин не публиковать, ведь публикацией и обсуждением я не нанес никому ущерба, не так ли?

Стоит ли использовать говно и палки для строительства, когда у вас есть бесплатные пеноблоки?

«Ваши родители знают, что вы — гей?» Мы в детстве тоже баловались такими же «вопросами», ага ))

Постарайтесь объяснить какие именно характеристики фреймворка были вам важны когда вы принимали такие решения. Это всегда интересно.

Нет вопроса. Есть пожелание. Пожелание принимается — будет серия статей.

Просто не понял зачем. Зачем делать «все массивами» и т.п.

Нет вопроса. Есть констатация вашего непонимания.
Вы считаете, что вопрос характеризуется исключительно знаком вопроса в конце предложения? Яснопонятно.

Ну тогда вот вам прямой вопрос, который задавлся выше:

ЗАЧЕМ?


Вы постоянно просто уходите от ответов, выкручиваетесь и юлите. Дело ваше, конечно, но конструктивную беседу таким образом не выстроить.
ЗАЧЕМ?


Господь с вами, я вам уже раза три на этот вопрос ответил. Что же мне сделать, если вы прочесть ответ не можете?

Еще разик давайте, мне же не сложно: затем, что могу. Мне так захотелось. Не вижу причин не публиковать, ведь публикацией и обсуждением я не нанес никому ущерба, не так ли?
У меня с мыслительными процессами сегодня туго, так что на всякий случай еще раз для себе уточню в последний раз, тем более, вам не сложно)

То есть мы имеем фреймворк, написанный ради того, чтобы написать фреймворк и статью, написанную ради того, чтобы написать статью. Я все правильно понял? Ничего не упустил?
Неверно.

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

Написана библиотека ради того, чтобы собрать в одном месте и в одном стиле ряд накопившихся за многие годы решения. И благодаря тому, что я могу и хочу это сделать.

Статья написана для того, чтобы показать сообществу библиотеку. И опять же благодаря тому, что захотел написать.

Если перефразировать так — то вы ничего не упустите.
Как это коррелирует с Вашими предыдущими ответами на те же самые вопросы? Вы так гордо и высокомерно отвечали сначала одно, теперь говорите совершенно другое. Где же правда-то в итоге?
Не готов вам ответить на вопрос. Не думаю, что он вообще требует ответа.

Вы находите какую-то «гордость» и «высокомерие» в каких-то совершенно технических текстах. Я не умею общаться в таком ключе, извините.

Мне интереснее обсуждать код, а не те эмоции, которые у вас он вызывает.
От обсуждение кода Вы точно так же уходите.
Отбросьте из моего поста слова «так гордо и высокомерно» и ответьте, пожалуйста, на поставленный вопрос. Так-то он имеет прямое отношение к коду. А вы опять убегаете от ответа.

Как это коррелирует с Вашими предыдущими ответами на те же самые вопросы? Вы отвечали сначала одно, теперь говорите совершенно другое. Где же правда-то в итоге?
Оставлю вас в вашем собственном мире, где «гордость», «высокомерие», «убегают от ответов», а вы рыцарь на белом коне, несущий правду. А сам останусь в скучном мире программирования ))

Однако с удовольствием отвечу вам на конкретные вопросе о коде данной библиотеки. Если я какие-то из них пропустил — не сочтите за труд повторить, пожалуйста.
я вам уже раза три на этот вопрос ответил.

Вы сказали что вам "захотелось". Вы опубликовали. Только читателям тоже надо дать какую-то мотивацию разбираться в том что вы придумали. Вдруг у вас что-то интересное, а тем самым вы отбиваете у читателя желание разбираться. Зачем? Прост.

Вы так и со студентами? Был задан вполне конкретный вопрос:


Зачем делать «все массивами» и т.п.

Ответили бы что мол "есть разница между массивами и коллекциями", что мол все ради type safety, что null-object-ы вместо неопределенностей… Вы же ответили "постарайтесь понять".

Автору следует посмотреть сюда — https://github.com/auraphp потому что
Делаем его слабосвязанным набором библиотек, так, чтобы каждую либу можно было подключить и использовать отдельно.
Стараемся сохранять здоровый минимализм там, где это возможно
Сам каркас для веб- и консольных приложений — тоже одна из библиотек, тем самым мы избегаем монолитности.
Стараемся не изобретать велосипеды и максимально сохраняем те подходы и тот код, которые уже зарекомендовали себя в T4.
Отказываемся от поддержки устаревших версий PHP, пишем код под самую актуальную версию.
Стараемся делать код максимально гибким. Если можно — вместо классов и наследования используем интерфейсы, трейты и композицию кода, оставляя пользователям фреймворка возможность заменить эталонную реализацию любого компонента своей.
Покрываем код тестами, добиваясь 100% покрытия.

все там уже есть
А чего нет — можно взять компоненты Symfony, Zend, Laravel и кучу нужных библиотек
Автор (и авторы) внимательно смотрели туда. Однако пока что ни один коммент на хабре не заставил их заплакать и отказаться от развития своих библиотек. Наверное, в этом что-то есть?
если какую-либо задачу ваши библиотеки позволят решить быстрее и эффективнее чем существующие инструменты — то почему бы и нет
правда пока что этого особо не видно — нет примеров реальных приложений, лично я пока не могу представить где ваши творения использовать
лично я пока не могу представить

Остаётся только надеяться, что однажды сможете!

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


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


В одном из комментариев Вы чуть-чуть наезжаете на Yii2. Скажу честно, что у меня самого в закромах есть статья которая сравнивает Yii2 и Symfony, причём не в пользу первого.
Я исправлял её уже очень много раз и изучал все моменты, и именно поэтому статья не опубликована и не никогда не будет. Это слишком разные проекты.
Да, мне не нравится ActiveRecord, но я стараюсь найти обходные пути или просто следовать best practices, т.к. это только часть фреймворка, так же как и поведения (мне они тоже не по душе).


Попробую посоветовать Вам поработать с разными языками: Java, Python, c++. У каждого свой подход, свои плюсы, минусы, ниши. Возможно, после code review от специалистов в этих языках Вы сможете более точно понять их назначение и область применения, равно как и PHP и ниши, на которые может быть нацелен Ваш Фреймворк.


В любом случае желаю Вам успеха и профессионального роста!


P.S. Прошу прощения за возможные грамматические и орфографические ошибки — пишу с телефона, перед сном, после кружки средства от простуды =)

Не извиняйтесь за ошибки, все мы люди, все ошибаемся.

В одном из комментариев Вы чуть-чуть наезжаете на Yii2

Наезжаю? Вы шутите? Я считаю его примером анти-дизайна и анти-проектирования, и как подобный пример всегда подаю студентам.
Это настолько нелепая архитектурная конструкция, что даже не знаешь, с чего и начать его разбор :) Наверное с самого факта его существования :)
UFO just landed and posted this here
нескольких крупных проектах

Мне просто для статистики, как вы "меряете" размеры проекта?

Дело известное, берешь линейку, берешь свой проект, проект своего соседа и замеряешь. Бездуховно это только…

Что отпугивает сразу:


  • полное отсутствие вменяемой документации. Без этого можно забыть даже о каком-либо успехе.
  • Ваши коллекции не скейлятся. Просто ненужные элиасы для массивов (вроде uksort) без возможности добавить новые методы, даже нет попыток как-то улучшить API на который так жалуются пользователи.
  • Вы упомянули и не раз что Yii это пример анти-проектирования, однако в вашем коде практически везде поощряется расширение за счет наследования. Как по мне это самый жирный минус Yii (с остальными можно мириться) который перекочевал к вам.
  • количество бесполезного кода зашкаливает. В частности в библиотеке с VO.
  • компонент валидации содержит помимо валидации еще и санитайзинг. Причем это просто ненужная объектная обертка над filter_var. Она не дает никаких преимуществ, мы ни композиции правил построить толком не можем ни что-либо переопределить толком. Та же история и с валидаторами — выглядит неюзабельным.
  • компонент для работы с файлами… не понятно почему File мутабелен. Опять нет четкого разделения ответственности. работа с файлами почему-то смешана с сериализацией, непонятно зачем. Забили на инкапсуляцию.

Словом вы выложили в опенсурс то что используете сами и пользуетесь только вы (если вообще используете). Работы над грамотным проектированием не производилось — на вид стихийное решение ваших прикладных проблем без оглядки и анализа существующих решений. Судя по состоянию репозиториев это что-то типа "ну мы тут с пивом собрались на выходных и решили запилить фреймворк".

После того как я открыл для себя Phalcon — на другие фреймворки даже не смотрю, фундаментально другой подход в компиляции сделал для меня погоду. Все фреймворки делают одно и тоже, зачем углубляться так глубоко в встроенные методы фреймворка, по сути нужен роутинг и структура для правильной организации кода. Чей фреймворк быстрее — тот я и использую со своими библиотеками.

на другие фреймворки даже не смотрю

А зря. У разных проектов есть разные нужды, которые разные фреймворки удовлетворяют по-разному, понимаете о чем я? Бывает очень удобно настрочить очередную безумную идею на Laravel. Бывает, нужна гибкость Zend Framework, иногда фреймворк вообще ненужен.
Я понимаю о чем вы говорите, но я с вами не согалсен. Все относительно, я считаю, что большинство фреймворков имеют очень низкого качества встроенные методы и слишком универсальные.

Написать свой конструктор запросов займет — 2 дня с высокопроизводительными запросами. Например, мне нужно всего-лишь поменять названия функции $Sql->insert() на $Sql->insertInFile() и у меня будет вставка через LOAD FROM FILE csv (имею ввиду, что именно функция сама запишет массив данных в csv и загрузит его, вместо INSERT запросов), автоматическая, зачем мне фреймвокр и их непонятные 100-ые решения для CRUD

Фреймворк — это структура, если есть удобный Роутинг + Контроллер + Шаблон + Модель + Компонент — все, фреймворк можно использовать — любой.

Я выибарю Phalcon — потому что он скомпилирован как модуль к php, соотвественно не нужно комплировать php файлв фрейворка, что есть огромное преимущество для проектов, которые парятся о нагрузке.
Я себе еще сделал одно упрощение, которое тоже всем рекомендую. Все мои кастомные проекты API based. Даже если front-end на php шаблонировании. Сразу отпадает много вопросов выбора и появляются огромные возможности простейшого кеширования и ускорения.
Написать свой конструктор запросов займет

А как вы будете разделять инфраструктуру от бизнес логики? Мне на самом деле интересно было бы послушать как люди организуют свой persistence layer. Используете ли вы DAO, мэпите ли результаты выборок на объекты для операций записи (на чтение пофигу, давайте только про выполнение бизнес-транзакций). Банальный пример. Есть у вас например необходимость сделать чатик на PHP (только запись и хранение истории сообщений), как бы вы организовывали следующую логику:


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

Желательно с хоть каким псевдокодом на gist. Реально интересно. Да, логика простая, но не хочу усложнять пример.


соотвественно не нужно комплировать php файлв фрейворка

А это простите зачем? Типа трюк с конкатенацией часто загружаемых файлов? Он не актуален с версии 7.0 при включенном opcache.

У меня это модель, где отдельная функция проверит связку пользователя и конверсейшена только по id через таблицу связей user_id conversation_id, после проверки — сообщение просто отпавлю в бд с данными после проверки прав. Вызываеть функции будет контроллер по очереди.

Нотификация будет происходит асинхронно отдельным скриптом а не в момент отправки сообщения, проверяя за раз много сообщений.

Вы серьезно сталкивались с проблемами производительности PHP на проектах с высокой нагрузкой? То есть вот прям именно не криворукий код, не работа с БД, не дебильные выборки и сортировки, а именно производительность PHP?

Фреймворк — это структура


Вы конечно правы, но у меня часто бывает так, что от фреймворка я беру отдельные компоненты, а вот структуру делаю свою. Ту, которая удовлетворяет потребностям проекта.

В последнее время все чаще выбор падает на отказ от фреймворка вовсе. Благо, теже компоненты symfony прекрасно работают и без самого symfony)

Но тем не менее, если завтра ко мне придут и скажут, что мне нужно сделать блоговый движок для нашей компании, то я лучше возьму и накидаю за пару часов что-то на Laravel. Если ко мне придут и скажут, что мне нужно напилить RESTFull API к существующей БД СРОЧНО, то наверное я возьму какой-нибудь Zend с Apigility и быстро решу поставленную задачу.

Конечно, мои примеры высасаны из пальца, но это просто для удобства объяснения. И да, я работаю с проектами, которые довольно сильно парятся о нагрузке. И в тех местах, где это действительно важно на уровне языка программирования — мы просто не используем PHP, вот и все. Но в 99% случаев, проблемы с производительностью кроются вовсе не в PHP и какой-то там компиляции. Тем более, что есть opCache.
Да, мои клиенты экономят сотни долларов на серверах, котому что они лажатся занчитель позже. У классических фреймворков такой же эфект как у Wordpres — серьезрый response delay под нагрузкой (у второго и без нагрузки) из-за огромног количества фреймворковских файлов. Есть бенчмарки, можете сравнить.

— Вы абсолютно правы про криворукость запросов и именно такими их делают криворукие разработчики по документации того же Yii
У меня ваши поставленные задачи решены уже на одном фреймворке. Ведь эти сушности стары как мир, сколько можно под них подстраиваться, нужно ими управлять.

Кстати php 7 очень быстрый, я тестировал на миллионом цикле с матиматикой и записью в массив. Проиграл 1-2 секунды C# и NodeJs и обошел Python на 30 секунд. (Тест конечно не супер лаборатоный), но меня порадовало, для меня больше важна скорость массивов и циклов.

Ну я фанат универсальных решений и люблю php, у меня под php есть многоядерная библиотека на локальной машине так и по сети. Можно взять огромный массив и попросить обработать соседние сервера. Так что я немного больной в этом плане, потому я подгоняю все решения под «условную автоматику».
У меня ваши поставленные задачи решены уже на одном фреймворке. Ведь эти сушности стары как мир, сколько можно под них подстраиваться, нужно ими управлять.


Я специально для вас сделал ремарку, что примеры высосаны из пальца. Само собой в реальности они совершенно другие, но я почему-то подумал, что вы сами сможете придумать себе пример. Если нет — дайте знать, выдам вам один из сотен «боевых» примеров.
Так разговор о фреймворке или криворукости разработчиков, не смешивайте теплое с мягким)

экономят сотни долларов на серверах


У меня есть очень большие сомнения в том, что вы когда-либо проводили тестирование вида: Ваше решение на Phalcon vs решение других ПРОФЕССИОНАЛОВ на любом другом фреймворке. Так что экономия тут — скорее ваша придумка, хотела и оправдание. Если уж говорить в таком ключе, то PHP вы вообще зря выбрали — не самый быстрый и надежный язык.
https://systemsarchitectdotnet.files.wordpress.com/2013/04/php-benchmark.png

Быстро, чтобы не тратить время. Можно придиратья, но картина по дургим тестам такая же, то есть вы считаете, что такое количество запросов в секунду не на что не влияет и совершенно не помогает переживать те же DDOS, когда фильтры хостера бесполезны и вы фильтруете софтерно. Еще как.

Недостаток таких тестов в том, что они проводятся на hello world или на чем-то сильно примитивном.


Do not trust benchmarks you didn't fake your self.

Вы считаете, что Hello word не достаточно? Это же первый вход — а дальше ваши кривые руки

Я фанат сосбтвенного кода, потому для меня это важно, я просто не использую много встроенных методов.

И вот вы все программисты и я не могу понять, почему вам не понятна разница самого факта, что Symfony — php, а Phalcon — C, то ест ьвы реально сравниваете доставку сервером php и скомпилированого C?
Разговор был об экономии сотен нефти конечному заказчику. А из того, что вы скинули никак не следует то, что это позволяет хоть как-то экономить. Еще раз напомню про opcache. Более того, выше мы вроде как уже обсудили, что PHP редко бывает самым узким местом приложения.
Мы так много времени на это потратили, хочу вернуться к работе.

У каждого из нас свой подход. Я считаю, что чем меньше звеньев в технологии — тем она стабильнее и надежнее.

Я очень скользко привел выше пример экономии.

Под DDOS атакой проект ложится намного позже. Часто просто продолжает медленно работать.

opcache — вариант конечно.

— Мое мнение, что разработчик должен решить две задачи:
1) Быстрое производство
2) Производительность

Остальные типа качества подразумеваются.

Phalcon более быстрая платформа из коробки, безусловно скорость фреймворка не решает насущих проблем производительности больших баз данных и больших обработчиков, но если мы говорим про емкие CRUD, где все и так оптимизирвоано и остается только роутинг, то только opcache вам в помощь и ничего плохого в этом нет, это ваш выбор )
Соглашусь) Ушел работать недождавшись Вашего ответа даже.

Главное, что б денюжку платили и заказчики довольны были. А вот как именно это уже не так важно.
емкие CRUD

в доброй половине из этих проектов можно просто взять firebase и не возиться с php.

а трудоемкость разработки на С и PHP не пробовали сравнить? Стоимость работы програмиста ща гораздо больше стоимости железа.
Если вы говорите про 50 долларов в месяц за Digital Ocean, то да )

Только я не понял вопрос про С и PHP, на Phalcon вы работает под PHP, сам фреймворк на C и его файлов нет в вашем проекте.
PS. Трудозатраты на разработку решения, которое работает быстро — очень преувеличены. По сути сейчас почти все мои решения «максимально быстры», покрайней мере на «мои мозги», может кто-то лучше программирует чем я. Но я сразу все библиотеки ориентирую под производительность.
Вы считаете, что Hello word не достаточно?

Ну тип того, да. Предположим разница между двумя фреймворками при таком тесте — фреймворк Б в 100 раз быстрее A. С другой стороны под фреймворк А в 50 раз больше разработчиков. Стоимость одного сервера за месяц составляет 1% от стоимости разработчика за тот же месяц. Так же предположим что на 10 разработчиков нам подходят 2 и 1 не пройдет испытательный срок (цифры с потолка и все зависит от проекта, на простых проектах цифры намного позитивнее).


Предположим что на реальном приложении мы упираемся уже не в CPU а в IOPS и сеть. И разница между фреймворками А и Б в плане RPS уменьшается до 2x. Для того чтобы добиться того же уровне RPS нам нужно 2.1x серверов (2.1 потому что резервирование железа и это не является 2.1x от всего кластера, это лишь php машинки). Так же не забываем что нам сложнее будет искать разработчиков. Искать людей которым плевать на чем писать и они все делают хорошо — это еще больше времени и денег. А далее уже надо смотреть на соотношение количества серверов к количеству разработчиков. И это мы еще делаем предположение что скорость разработки и инфраструктура у обоих фреймворков развита примерно одинаково.


tl;dr математика простая. Если у нас много серверов — мы получаем профит, но это должен быть реально большой кластер чтобы был профит. Потому хотелось бы знать заранее соотношение rps для более-менее реального проекта. А это уже сложно потому что надо делать.


p.s. hello world на php7 выдает на 30% больше RPS чем phalcon3.

С вашими словами согласен, но что делать если вся команда принимает проекты под ключ и делает их на Phalcon в рамках своего тех процесса и проводит обучение разработчиков по собственным наработкам — в таком случае ваш аргумент про найм сотрудников не имеет веса.

И я еще не видел сотрудников по php, которые бы не могли разобраться в любом фреймворке, сотрудников которых вы описали — это планка ниже 500$ в регионах. От 700$ в регионах — уже всеравно на чем писать, другой вопрос — общее качество на любом из фреймворков.
Вы тоже все описали слишком «лабораторно», в реальности, пока вы пишите код — ваш фреймворк все замедляется и замедляется. Не круто получать тяжеловесный шаблон например через 500ms или что еще хуже через секунду.
доставку сервером php и скомпилированого C?

Какая разница если 80% времени PHP тупо ждет блокирующих операций ввода/вывода?

Ну и безусловно иногда подразумевается, что при принятии подобных решений проводятся собственные субьективные тесты. Как выше мне говорили, что php медленный. Я думал, где мне обрабатывать 10 гигабайтный массив, в php,C или Node, провел тест php7 и в реальном испытании он показал отставание на секунду. Так же проводил тесты по нагрузке на сервера.

Один из тестов попал и Wordpress, он тоже попал под жесткую оптимизацию и вам советую, если делаете на WP сайты напишите в index.php перехватчик буфера вывода и кешируйте его в БД, получится скорость сайта из 1 php файла и одного запроса — полностью отрубаете WP компиляцию
серьезрый response delay под нагрузкой (у второго и без нагрузки) из-за огромног количества фреймворковских файлов
Почему то вы игнорируете все упомининия ваших оппонентов про opcache. Данные, которыми вы оперируете, устарели на несколько лет.
Вы правы, но эти споры — развлечения, по сути ниже правильно написали. Фреймворк быстрый, минималистичный и он меня устраивает.

А что именно не так в документации Yii по запросам?

на другие фреймворки даже не смотрю

Ну да. ведь все задачи на свете можно подогнать под один единцы универсальный подход. Если вы просто смотрите на другие фреймворки/языки это не обязывает их использовать. Можно просто духовно развиваться.


фундаментально другой подход в компиляции

Это как простите? подход то тот же абсолютно.


так глубоко в встроенные методы фреймворка

Ну инструмент то свой нужно. К слову, поделитесь историями о том как вы дебажите приложения, можно ли xdebug-ом залазить внутрь внутренних вызовов и смотреть что там происходит?


структура для правильной организации кода

В бородатых 70-х придумали такие штуки как coupling и cohesion для грамотной декомпозиции проекта на модули. А когда фреймворк заставляет меня ложить все в сontroller и model я грущу.


К слову может будет интересно. Тут есть прекрасно поданный материал на тему структурирования кода. Правда в контексте Java но это не столь принципиально.

Спасибо.

Да, вы меня правильно поняли, чем не устраивает универсальный и самый производительный подход, разве не это вам позволяет делать фреймворк?

И на практике, не могли бы вы привести популярные, а не супер частные случаи, где фреймворк имеет значение? Разные команды делают похожие проекты на абсолютно разных фреймворках.

Духовно развиваться нужно, но не считаю, что фреймворки — это пища для развития. Безусловно я пересматриваю свой подход разработки регулярно, меняю фреймворки, как недавно поменял Ember на Angular 2, но по возможности я не начинаю новые проекты на двух сразу.

Вот не могу себе представить, где лучше будет Ember чем Angular и наоборот — только мои предпочтения.
разве не это вас позволяет делать фреймворк?

Я использую Symfony, он позволяет мне не использовать то что мне не нужно. Так что я в целом доволен. А сам по себе фреймворк не является в моем случае узким местом, тут скорее инициализация контейнера зависимостей уже больше будет влиять. А вообще у меня тут есть маленький пет-проджект, надо бы все же попробовать его реализовать на phalcon. Уже года 2 собирался потыкать этот фреймворк тупо для расширения кругозора, да все небыло интереса. А так хоть нагрузочные тесты можно будет погонять что бы посмотреть стоит ли овчинка выделки.


что фреймворки — это пища для развития.

Я именно о таких штуках как "а не попробовать ли мне SPA делать заместо обычного WEB, вдруг устраню кучу проблем". Или "в symfony/flex замутили удобный скаффолдинг проектов, любопытно, сворую для фалькона".

Ну вот и вы написали, что все на ваших предпочтениях ) и все задачи по сути вы на Симфони и решаете (в целом если творчество не загорится)
вы на Симфони и решаете

типовые проекты — на своей сборке, некоторые специфичные задачи — на отдельных компонентах и не только на симфони компонентах.

Я именно о таких штуках как «а не попробовать ли мне SPA делать заместо обычного WEB, вдруг устраню кучу проблем».

SPA — это один из модных нынче трендов. Посему неважно какие проблемы он решает, какие еще большие проблемы создает и что конечному пользаку, как правило не айтишнику, пофиг SPA там или древний CGI,
неважно какие проблемы он решает,

для меня важно. Мы таким образом сильно упростили бэкэнды, а UI логика на SPA ложится просто прекрасно.


какие еще большие проблемы создает

незначительные на фоне профита на самом деле. Ну это если знать что делаешь. Вот тут могут быть проблемы.


пофиг SPA там или древний CGI,

Это влияет на UX причем неслабо, и уж поверьте рядовому пользователю разница тут будет огромна.

Мы таким образом сильно упростили бэкэнды,

и сильно усложнили фронтэнды. При этом без бэкенда на приложениях с серьезными данными все равно не обойдешся.

Все фреймворки делают одно и тоже,

Все языки программирования делают одно и тоже.
Все компьютеры делают одно и тоже.

На самом деле фреймворк важен не тем что он делает а тем насколько упрощает програмисту решение конечно задачи.
Другое дело что 9 из 10 фреймворков — архитектурные MVC-близнецы и поэтому их сложно разложить по направлениям решения (точнее имплементации задач).

Заглянул на Гитхаб...


Репозиторий Core. Core чего, фреймворка? Но он же слабосвязанный? И что во фреймворке такого, центрального, без чего фреймворк — не фреймворк?


О нет, это ядро всего приложения… Фреймворк не должен быть ядром приложения, ядро должно быть независимым ни от чего. Чисто практически — кто будет использовать интерфейсы или наследовать свои классы от никому не известной 3d-party библиотеки?


Storages/KeyValueStorage. Финт с null-овым именем для вызова мощного деструктивного поведения когда-нибудь дорого обойдется. Явное лучше неявного, почему бы не сделать методы loadAll/saveAll()?


Load data from external storage into this object by specified...? То ли впопыхах вкоряченный и забытый костыль, то ли тотальное непонимание ООП. От KeyValue клиентам нужно только одно — положить данные, а потом их забрать, им глубоко фиолетово, что там где-то за KeyValue есть еще одно external storage. Хинт: попробуйте реализовать этот интерфейс на базе memcached.


/**
 * Stores the value by specified key in this object
 * @param int|string|null $key
 * @param mixed $value
 */
public function set($key, $value);

Ключи "1" и 1 — будут считаться за один и тот же ключ или за разные? Укажите string, стандартного приведения типов достаточно.


Зачем Вам XxxStorageAwareInterface? Здесь не проглядывается ни одной причины для его использования. Выглядит особенно странно с учетом Вашего прохладного отношения к DI. Кстати, аннотации противоречат сигнатурам методов.


SingletonInterface, SingletonTrait. Нас настойчиво подталкивают к использованию синглтонов. В нормальном фреймворке должно быть легко делать правильные вещи и тяжело — неправильные.


SingletonTraitTest. Проверять рефлекшеном, что конструктор непубличный — это, пардон, днище. Класс нельзя инстанцировать через new — вот что надо проверять, не больше и не меньше. И дайте тестовым методам нормальные имена хотя бы.


Больше не смотрел. Общее впечатление — куча неважных, да еще спорных мелочей (типа FI), неочевидное поведение, везде наследование и магия, непонимание базовых принципов ООП, косяки на всех уровнях абстракции. Как это вообще можно выкладывать?

Большое спасибо за столь подробный комментарий.

Отвечу на последний вопрос: это нужно выкладывать, хотя бы для того, чтобы вы могли поупражняться в разборе :)

А если серьезно, то любые отзывы всегда на пользу. Положительные дают силы продолжать дальше. Отрицательные — возможность задуматься и вовремя что-то изменить. Большое спасибо, что пишете их!
Sign up to leave a comment.

Articles