Открыть список
Как стать автором
Обновить

Комментарии 71

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

И это написано в защиту статьи "простой современный MVC-фреймворк"?

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

Зачем? Есть, знаете ли, маленькая разница между "я понимаю, как устроено" и "я знаю, как написать".

Я писал весь код исключительно для повышения своей квалификации как программиста.
Так как просто читать «о программировании» — это не то.
Надо ручками, ручками — кодить, думать, анализировать.

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


Приведу пример:


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

А вот если бы вместо этого вы бы просто на PHP написали логику какую сложную, поработали со структурами данных, написали бы e-commerce решение (только логика, ни баз данных ни прочего) с какими-нибудь сложными скидками и купонами, вот там есть где покачать скил. Особенно если при "качании скила" наложить кучу ограничений на свой код (аля никаких геттеров, ну или взять просто "объектную гимнастику"). Вот эти ограничения вас думать заставят. Ну или попробовали бы по TDD работать (phpspec желательно, ну или хотя бы phpunit, а не codeception который позволяет тестить любой код) отбросив все свои старые привычки. Это тоже будет "чем-то новым" для вас.


А так… просто еще один фреймворк который не должен увидеть продакшена.

Спасибо за идеи куда «расти», как специалист. Я тоже подумывал о чем-то подобном.
Хочется интегрировать программную составляющую (что писать: структуры, сложная логика, объекты и т.п.) и общественно-полезную составляющую (для кого для чего писать, суть самой разработки, её полезность для людей).
и общественно-полезную составляющую

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


Посмотрите чего не хватает инфраструктуре PHP. Я бы например предложил бы вам сделать солюшен вроде attache, и даже звездочку бы поставил.


Еще как вариант — leaderboard для PHP, потом возможность истории впилить.


Еще — можно попробовать попилить фичи для популярных библиотек/фреймворков.

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

Презентацию очередного фреймворка лучше всего со сравнения с существующими. Так читатель может понять, на какую нишу этот фреймворк претендует. Для этого нужно хорошо разбираться в существующих решениях. Если же вы начали писать свой ради того, чтобы не изучать чужое, вас ждет сизифов путь.
$loader->addPsr4('framework\\', __DIR__. '/../../system/');
$loader->addPsr4('frontend\\', __DIR__. '/../');
$loader->addPsr4('common\\', __DIR__. '/../../common/');


это же можно вынести прямо в composer.json
А как?
Я пробовал отключать этот код — но тогда ничего не работает.
Добавлял такие конструкции:
"psr-4": {
"Frm\\": "/system/",
"App\\": "/application/"
}

Но не дошел до работающей конструкции.
:(
Добавлял такие конструкции

А после добавления файл автозагрузки пересобирали?
Добавлял и пересобирал (пробовал разные способы).
На досуге попробую ещё. Спасибо, что подсказали, что так можно сделать. Конечно, подобная конструкция не очень красива.
"autoload": {
		"psr-4": {
			"Migration\\": "migration/"
		}
	}


/system/ — это от корня, потому и не работает ;)
/system/ — это от корня, потому и не работает ;)

как это связано?

"Имя Ибрагим ведущий слеш вам о чём-нибудь говорит?")

"Migration\\": "migration/"

Просто для контраста? Тогда понятно. А я пошел в репе автора искать, где же там у него миграции )
«Хотел бы услышать, можно ли на данном решении стартовать реальный проект?» — я правильно понимаю, что вы что-то создали, но не понимая насколько оно жизнеспособно просите оценить со стороны?
После какого-то этапа разработки фреймворка его можно применять «в жизни», на реальных проектах.
Мне кажется, что для текущей конструкции этот этап уже наступил — т.е. фукнциоанл перевалил за какую-то граничную точку, когда это уже не учебный проект, а нечто самостоятельное и жизнеспособное.

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

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

Нет, не надо применять это "на реальных проектах", пожалуйста. Миру уже хватает проектов на no-name фреймворках которые нереально суппортить.


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

Я вот тоже к тому же прихожу: ОРМ хочется взять стороннюю, а так же и шаблонизатор, мейлер…
Можно немножко критики?

— почему неймспейсы начинаются с маленьких букв?

— вашей целью было использовать всю мощь языка — а везде конкатенации вместо двойных кавычек

— что за прикол с двумя конфигами которым нужно ещё и array_merge делать? как минимум странно

— что за прикол с путями в стиле "/../../system/"? почему нет константы корневого пути проекта вместо этого?

— зачем у вас есть свой класс исключений типа CoreException, если вы строите строку-сообщение вручную, вместо передачи грубо говоря реквеста и всё? зачем новый класс если он судя по всему ничего не делает?

— Не вопрос а просто критика — местами есть очень сомнительный код, типа вот такого:
foreach ($this->response->getHeaders() as $header) {
    header($header);
}


P.S. Всё выше — чисто моё ИМХО, на истину в последней инстанции не претендую

Полагаю, что пространства имен с маленькой буквы навеяны Yii2. Не вижу ничего плохого в этом. Стандарт PSR-4 об этом умалчивает, поэтому это дело вкуса как их обзывать.


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

в yii то понятно это так сложилось, это их стиль и всё такое, но все пакеты нынче используют UpperCamelCase. Так зачем следовать за таким редким стандартом. Да и смотрится потом при использовании сторонних пакетов это стремно.

Да, я считаю что нет смысла расширять класс исключений только ради нового названия класса. Зачем плодить новую сущность которая отличается от встроенной в язык только названием?
Присоединяюсь, к пред. высказыванию.
Как на мой взгляд, расширяя базовый класс исключений, удобно писать сои обработчики на исключения и строить сою логику действий в этом случае.

Этим вы подтвердили мои догадки о том, что понятия не имеете как работать с исключениями.

что за прикол с двумя конфигами которым нужно ещё и array_merge делать?

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

Например: у нас есть фронтэнд, бекэнд и консоль. Коннект к БД хранится в одном файле.
В каждом приложении мы подключаем конфиг самого приложения и конфиг с настройками коннекта к БД.
Получается просто и универсально (ка на мой взгляд).
а если я с cli хочу конектится к другой базе?
Если требуется из CLI коннектиться к другой базе — то в конфиге CLI прописывается эта база.
В общем конфиге коннекта к этой базе нет, конфиги разделены.
Есть очень много способов решить указанную задачу. Я привел лишь один из них.
ну у меня в основном конфиге конект к основной базе, а в кли к другой. мы смержили конфиги и куда я приконекчусь?
Чтобы разрешить такие коллизии нужно:
1) Иметь в фреймвопке возможность задавать неогр. количество конфигов к БД.
2) Иметь возможность передавать в скрипт коннекта к БД один из выбранных конфигов.
Тогда будет универсальность и многовариантность применения.
Ну тоесть вы понимаете, что такой бездумный мердж может вызывать неочевидные проблемы
Ого, Вы изобрели урезанный Yii 2 :) Даже структура и названия директорий почти один в один.
Вы правы :)
С него структуру и копировал (но не только из этого фреймворка, источников кода было много).

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


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


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


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


Php как шаблонизатор если используете то имхо лучше использовать <?= ... ?> вместо <?php echo ...; ?> и для управляющих конструкций вариант синтаксиса с :. Т. е.


<?php foreach(): ?>
...
<?php endforeach ?>
Я не автор, но с вами немножко поспорю :) Шорт-теги (<?=) — зло, и использовать их нежелательно. А учитывая то что надо бы экранировать вывод в шаблонах (во избежание XSS) — так лучше ещё и нагородить свою функцию вместо echo). А синтаксис с : — оно то вроде как для вёрстки и задумано, но есть большой минус — редакторы кода не находят такие логические блоки, в отличие от блоков с классическими фигурными скобками.
Шорт-теги (<?=) — зло, и использовать их нежелательно

Потому что потому?

так лучше ещё и нагородить свою функцию вместо echo

<?= escape($data) ?>

Не вариант?

Функцию экранирования это само собой. Т. е. в идеале нужен нормальный шаблонизатор. Но если мы используем просто php шаблон то делаем функцию


/**
 * @param mixed $value
 * @return string
 */
function e($value)
{
    return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8', false);
}

и используем её: <?= e($some) ?>


Шорт-теги (<?=) — зло

У вас устаревшая информация. Во первых шорттеги считались злом потому что могут быть не включены. Но с PHP 5.4.0 именно <?= не считается шорттегом и директива конфигурации на него не влияет.


редакторы кода не находят такие логические блоки

Я не знаю чем вы пользуетесь. Мой шторм справляется. Но смысл что эти теги делают более читаемым код и без сворачивания

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

А вот по поводу шторма — только что пробовал, и мой шторм не воспринимает endif и endforeach как логические блоки, и следовательно не работают хоткеи перехода к логической скобке. Мы у себя на проекте пробовали использовать : синтаксис — но в итоге вернулись на классику, не понравилось. Но тут уже вкусовщина, спорить не буду.
По поводу шорт-тегов — признаю, как-то пропустил этот момент когда они перестали быть злом

Мне кажется вы не до конца правильно понимаете ситуацию. Шорт-теги остались злом. Но конкретно тег <?= к этому злу не имеет отношения, так как конфигурационная опция, связанная с шорт-тегами, на его работоспособность не влияет после версии 5.4.

У вас "неправильный" шторм


Работает же

image

Тюю. Пошёл тогда копать настройки шторма…
Еще очень просится разделить код самого ядра с его тестами и непосредственно приложения на его основе. Вынесите его в отдельный пакет.


Ага, пришел так же к этому (вообще узнал о такой возможности недавно).

лучше использовать <?=… ?> вместо <?php echo ...; ?>

Да, буду переучиваться себя на такой стиль.
Одно время были споры по поводу коротких тегов.
Рад что сообщество вернулось к <?=… ?>
А сессию вы используете всегда при любом запросе?
Получается, что всегда.
«Узких» мест много.
На своем опыте я понял, что чем больше пишешь — тем больше разрастается код, тем больше надо думать об архитектуре и общей схеме вызова компонентов.
Список «К исправлению» увеличивается и увеличивается, а для каждого исправления — надо много читать и думать об оптимальных решениях.
И тесты писать и прогонять их после каждого изменения в ядре.
Положительным моментом всей этой затеи является то, что квалификация и опыт программирования растет так же с исправлением каждой ошибки. Но цена этого опыта — перебор горы пустой породы в поисках того алмаза.
Хотя другого пути нет, никто за человека это не сделает, кроме него самого.
Говорил Чехов нехорошее, про людей, которые не умеют скрывать свои плохие повести… Велосипедить всегда хорошо, но для себя.

По коду. А что будет, если нам подсунули не инстанс контроллера?
                if ($controller instanceof Controller) {
                    $controller->setApplication($this)->run();
                }

Молча проглотим? Хотя если класс не существует, то кидаем исключение. Не аккуратненько…
Спасибо всем за критику, замечания и предложения.
Со «своей колокольни» не все видно (или видно недалеко), а так все накидали комментариев по чуть-чуть — понятно что с этим всем делать и что есть в сухом остатке на данный момент.
Похвально желание учиться, поэтому вместо критики лучше добавлю свои пару копеек к процессу обучения.

— Хранить пароли в md5 не стоит.
http://php.net/manual/ru/function.password-hash.php
https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet
— Модели уж совсем примитивные, нужно как минимум абстрагироваться от работы с PDO напрямую. Вообще я бы не рекомендовал учиться на примере Active Record, ничему хорошему не научит. Лучше возьмите готовый слой абстракции построения запросов, например Doctrine DBAL (там особо нечему учиться, но много рутины) и стройте поверх него свою ORM.
— Сила фреймворков в расширяемости и модульности, у вас же все компоненты очень тесно связаны, компонент авторизации например может работать только с вашей моделью User. На весь фреймворк у вас один интерфейс.
— Как дальнейшее направление для обучения — написать свой DI контейнер и диспетчер событий.
База данных: MySql >=5.4.*

Это что за зверь такой? После версии 5.1 сразу же идет 5.5
Почему почти все пытаются влепить AR в свой велосипед?

потому что это самый простой способ сделать взаимодействие с БД. Даже DAO сложнее потому что думать больше надо. А тут — есть табличка в базе и она 1:1 мэпится на объектик. Ну и еще — многие кроме AR ничего и не юзали.

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

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

Т. е. вы "практически ничего не использовал кроме AR" и при этом уверены что где то там солнце ярче?

Ключевое слово практически. Мое объяснение будет заключатся скорее всего в минусах AR связанных с магией и большой связанность. По мимо этого AR внес весьма солидную путаницу в разработку, а именно теперь большинство разработчиков, а в частности это новички, понимают примерно так:
модель == один класс == active record (я тоже так думал еще 2 года назад).

На примере Eloquent ORM: так есть такие понятия как аксессоры, мутаторы, скопы и тп. Работая со всеми этими терминами в контексте одного класса «модель» становится не много неповоротливой. Дальше более продвинутые новички, которые почитали про «MVC», и узнали примерно такую цитату "… Контроллеры должны быть тонкими, а логика должна быть в модели...", придерживаясь вышеупомянутого сравнения начинают логику писать в моделях (а в 99% это 1 класс).

В результате появляется весьма не очень хорошая практика и очень много не очень хороший статей и видео по теме.

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

А так все получилось, потому, что очень сложно объяснить новичку, который 10 лет пишет на AR, почему нужно создать еще 5 классов, а не один AR.
но он практически всегда приносит жесткий дискомфорт

Ну можете перейти на уровень выше — row data gateway. Это когда у вас над каждой "моделькой" или графом "моделек" представляющих именно модель данных, есть объекта модель которая представляет корень агрегата например.


Можно по разному готовить работу с базой данных. И вы редко ограничены каким-то одним подходом. Причем даже в одном проекте могут быть ситуации при которых надо комбинировать подходы.

Поэтому нужно как-то людей толкать в сторону сущностей, репозиториев и дата-маперов.

или DAO.

я сейчас сделал не много по другому.
— сущность
— репозиторий
— для некоторых вещей View Model

А вот реализация уже использует AR. И то очень аккуратно, так как строить запросы в нем очень легко. А с помощью View Model иногда можно возвращать кастомные штуки, чтобы не плодить частичные объекты (http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/partial-objects.html).

В теории я тестировал, реализацию можно подменить без проблем, так как на выходе единый формат сущности или view model

Кто у вас отвечает за сохранение сущности (кто дергает save)? Как разруливаете связи? Что у вас является сущностью? Выделяете ли корень агрегата сущностей?


чтобы не плодить частичные объекты

partial objects из доктрины слегка бесполезная штука. Мне больше импонируют выборки с select new SomeDTO(u.id, u.name)...;


Тут проблема в другом. Вам действительно все это надо? Особенно например репозитории (я так понимаю что у вас нет UoW). Ну и в целом посмотрите в сторону row data gateway, я подозреваю что вы что-то подобное и сделали только сложнее.

Кто у вас отвечает за сохранение сущности (кто дергает save)?
За сохранение отвечает тот-же репозитроий. Хоть и во круг этого ходят холивары, однако репозиторий это абстракция над хранилищем, поэтому думаю, что методу «сохранить в хранилище» место в репозитории, ну и пока на практике не узнал обратного.

Как разруливаете связи?
AR. Тоесть репозитории и сущности это такая себе абстракция над AR в моем случае.

Что у вас является сущностью?
Взял идею из Symfony. Тоесть у меня есть несколько понятий DTO — класс только с геттерами, который я гоняю между модулями и Сущности, которые в основном находятся в главном модуле Application, и являются практически идентичными как в Symfony.

«я так понимаю что у вас нет UoW»
Да, UoW пока нет, мы только начали пилить проект и подобные штуки я взял на себя смелость внести на этап оптимизации.

Тут проблема в другом. Вам действительно все это надо?
Как показывает практика, если Вы за рамками «бложика» или «сайта-визитки» и требуется постоянно допиливать и обновлять функционал, то подобные вещи весьма кстати.
Хоть и во круг этого ходят холивары

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


Взял идею из Symfony.
являются практически идентичными как в Symfony.

Тут подробнее. У вас там геттеры/сеттеры или полноценная объектая модель, с логикой в сущностях и тд.


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


смелость внести на этап оптимизации.

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


Если вы это уже разруливаете руками, я не вижу смысла уже делать UoW. Но тогда мне было бы интересно узнать как вы это разруливаете.


то подобные вещи весьма кстати.

Ну для того что бы объективно оценить надо все же видеть код, просто как по мне у вас слишком уж резкий переход от простого active record к DDD-ной структуре. Да и AR не мешает делать DDD, просто будет больше похоже на row data gateway нежели обычный ar.

у вас не очень то и репозиторий, больше походит на table gateway.
Ну тут спорный вопрос, так как данные одной сущности могут быть раскинуты на несколько таблиц. К примеру есть сущность Product, у него есть поля name, description и тп. и данные этих полей могут быть в таблице скажем product_translations (да я пока не решился отойти от этого подхода в пользу json).

Тут подробнее. У вас там геттеры/сеттеры или полноценная объектая модель, с логикой в сущностях и тд.

Видимо не натыкался я на примеры с логикой, но в моем понятии сущность — это класс с геттерами и сеттерами, который ничего не делает, кроме как позволяет предоставить контейнер для данных сущности. Как-то я уже натыкался на весьма серьезную проблему (https://habrahabr.ru/post/316836/) и сущности рассматриваю как обертку над данными и единый формат, который можно гонять по проекту, ну скажем если подменить хранилище, то оперируя сущностями приложение не должно заменить, что что-то пошло там поменялось.

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

UoW нужен не для оптимизации
Походу его основная задача, это (с) "… Реализация паттерна Unit of Work следит за всеми действиями приложения, которые могут изменить БД в рамках одного бизнес-действия. Когда бизнес-действие завершается, Unit of Work выявляет все изменения и вносит их в БД. ..."

у вас слишком уж резкий переход от простого active record к DDD-ной структуре
Много обжигался. Однако не совсем DDD у меня, скорее просто модульная архитектура и стараюсь следовать SOLID. Сейчас мы пилим API, и возможно версия 2 будет разбита на микросервисы и некоторые даже начнут жить по DDD. Однако сейчас просто нет финансовой возможности позволить «жирных» специалистов. Клиент скорее наймет 5 человек за $5000, чем одного. Поэтому как минимум я весь опыт черпаю из неудачных решений проходя через собственные ошибки.

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

А это уже спрятано за уровень абстракции, так что не столь важно.


но в моем понятии сущность — это класс с геттерами и сеттерами

Рекомендую почитать про такой термин как "анемичная модель". Если коротко — это такая модель которая налагает ту же сложность что и обычная, но не приносит профита поскольку ничего не делает.


А с примерами туго, согласен.


просто модульная архитектура и стараюсь следовать SOLID

Если с тестами и именно юнит тестами, тогда все хорошо)

Что касается темы, то мне точно не хватает статей на PHP про:
— DDD
— Entity / VO / DTO
— Repository

и тп.

Ну и Вы про всякие гексагональные архитектуры весьма редко пишите.
точно не хватает статей на PHP про:

Начните с синей книги Эрика Эванса. Там это все тесть. И вы забыли про агрегаты сущностей, bounded context и т.д.


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

Я вообще редко пишу… Да и гексагональная архитектура — это один из вариантов построения приложений. Нужно понимать какие характеристики дает та или иная архитектура и думать надо ли вам это или нет.

Ну вот я не леплю :)
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.