У меня есть для вас непростое задание. Когда в следующий раз начнёте новый проект, постарайтесь обойтись без PHP-фреймворка. Я не собираюсь перечислять недостатки фреймворков, и это не проявление синдрома неприятия чужой разработки: в этом руководстве мы будем использовать пакеты, написанные разработчиками нескольких фреймворков. Я всецело уважаю инновации в этой сфере.
Но эта статья не о них. Она о вас. О возможности стать лучше как разработчик.
Возможно, главным плюсом отказа от фреймворка станет знание, как всё работает под капотом. Вы будете видеть, что происходит, не полагаясь на фреймворк, который заботится о вас настолько, что вы не можете что-то отладить или до конца понять.
Возможно, ваша следующая работа не позволит вам насладиться запуском нового проекта без фреймворка. Многие важные, критические для бизнеса PHP-задачи подразумевают использование уже существующих приложений. И неважно, будет это приложение, построенное на современном фреймворке вроде Laravel или Symfony, на одной из старых платформ вроде CodeIgniter или FuelPHP — либо это удручающе широко распространённое легаси PHP-приложение с «include-oriented архитектурой»: если сейчас вы будете разрабатывать без фреймворка, то окажетесь лучше подготовлены к любому будущему PHP-проекту.
Раньше создавать без фреймворков пытались потому, что некоторые системы вынуждены интерпретировать и маршрутизировать HTTP-запросы, слать HTTP-ответы и управлять зависимостями. Нехватка стандартов неизбежно приводила к тому, что как минимум эти компоненты фреймворков были тесно взаимосвязаны. Так что если вы начинали разрабатывать проект без фреймворка, то в конце концов приходили к созданию своего собственного фреймворка.
Но сегодня благодаря стараниям PHP-FIG в сфере автозагрузки и взаимной совместимости вы можете разрабатывать без фреймворка, не создавая его попутно. Существует множество замечательных, взаимно совместимых пакетов, написанных многочисленными разработчиками. И собрать их в единую систему гораздо проще, чем вы думаете!
Как работает PHP?
Прежде всего важно понять, как PHP-приложения взаимодействуют с внешним миром.
PHP исполняет серверные приложения в цикле запрос/ответ. Всё взаимодействие с приложением — из браузера, командной строки или REST API — приходит в него в качестве запросов. При получении запроса приложение загружается, обрабатывает запрос и генерирует ответ, который передаётся обратно клиенту, а приложение закрывается. И так происходит при каждом обращении.
Контроллер запросов
Вооружившись этим знанием, начнём с фронт-контроллера. Он представляет собой PHP-файл, обрабатывающий все запросы к вашему приложению. То есть это первый PHP-файл, в который попадает запрос, и (по сути) последний PHP-файл, через который проходит ответ приложения.
Давайте воспользуемся классическим примером с Hello, world!, обслуживаемым встроенным в PHP веб-сервером, чтобы проверить, всё ли настроено корректно. Если вы этого ещё не сделали, то удостоверьтесь, что в среде установлен PHP 7.1 или выше.
Создадим директорию проекта, в ней сделаем вложенную директорию public
, а внутри неё — файл index.php
с таким кодом:
<?php
declare(strict_types=1);
echo 'Hello, world!';
Обратите внимание, здесь мы объявляем строгую типизацию — это нужно делать в начале каждого PHP-файла вашего приложения, — потому что подсказки типов (type hinting) важны для отладки и ясного понимания теми, кто будет заниматься кодом после вас.
Далее с помощью инструмента командной строки (вроде Terminal на MacOS) перейдём в директорию проекта и запустим встроенный в PHP веб-сервер.
php -S localhost:8080 -t public/
Теперь откроем в браузере адрес http://localhost:8080/. Отображается Hello, world! без ошибок?
Отлично. Переходим к следующему шагу!
Автозагрузка и сторонние пакеты
Когда вы впервые начали работать с PHP, то, вероятно, использовали выражения include
или require
для получения функциональности или конфигураций из других PHP-файлов. В целом этого лучше избегать, потому что другим людям потом будет гораздо труднее разобраться в коде и понять, где находятся зависимости. Это превращает отладку в кошмар.
Выход — автозагрузка. Это означает, что, когда вашему приложению нужно использовать какой-то класс, PHP знает, где его найти, и автоматически загружает в момент вызова. Эта возможность существует со времён PHP 5, но стала активно применяться только с появлением PSR-0 (стандарта автозагрузки, сегодня заменён PSR-4).
Можно было бы пройти через тягомотину написания собственного автозагрузчика, но раз мы выбрали Composer для управления сторонними зависимостями, а в нём уже есть очень удобный автозагрузчик, то его мы и будем использовать.
Проверьте, что у вас установлен Composer. Затем настройте его для своего проекта.
composer init
После этого пройдите через интерактивное руководство по генерированию конфигурационного файла composer.json
. Затем откройте его в редакторе и добавьте поле autoload
, чтобы получилось так, как показано ниже (тогда автозагрузчик будет знать, где искать ваши классы).
{
"name": "kevinsmith/no-framework",
"description": "An example of a modern PHP application bootstrapped without a framework.",
"type": "project",
"require": {},
"autoload": {
"psr-4": {
"ExampleApp\\": "src/"
}
}
}
Теперь установите для этого проекта Composer, которые подтянет все зависимости (если они уже есть) и настроит для нас автозагрузчик.
composer install
Обновите public/index.php
для запуска автозагрузчика. В идеале это одно из нескольких выражений include, которые вы используете в приложении.
<?php
declare(strict_types=1);
require_once dirname(__DIR__) . '/vendor/autoload.php';
echo 'Hello, world!';
Если перезагрузить приложение в браузере, вы не увидите никакой разницы. Однако автозагрузчик работает, просто он не делает ничего тяжёлого. Давайте перенесём пример с Hello, world! в автоматически загружаемый класс, чтобы проверить, как всё работает.
В корне проекта создадим папку src
и вставим в неё файл HelloWorld.php
с таким кодом:
<?php
declare(strict_types=1);
namespace ExampleApp;
class HelloWorld
{
public function announce(): void
{
echo 'Hello, autoloaded world!';
}
}
Теперь в public/index.php
замените выражение echo вызовом метода announce в классе HelloWorld
.
// ...
require_once dirname(__DIR__) . '/vendor/autoload.php';
$helloWorld = new \ExampleApp\HelloWorld();
$helloWorld->announce();
Перезагрузите приложение в браузере и увидите новое сообщение!
Что такое внедрение зависимостей?
Внедрение зависимостей — это методика, при которой каждая зависимость предоставляется объекту, которому она требуется, вместо того чтобы объект обращался наружу за получением какой-то информации или функциональности.
Допустим, методу класса нужно считать из базы данных. Для этого надо к ней подключиться. Обычно новое подключение создаётся с учётными данными, полученными из глобального пространства.
class AwesomeClass
{
public function doSomethingAwesome()
{
$dbConnection = return new \PDO(
"{$_ENV['type']}:host={$_ENV['host']};dbname={$_ENV['name']}",
$_ENV['user'],
$_ENV['pass']
);
// Make magic happen with $dbConnection
}
}
Но это не лучшее решение. На чуждый метод возлагается ответственность за создание объекта нового подключения к БД, получения учётных данных и обработки любых проблем в случае сбоя подключения. В результате в приложении дублируется масса кода. А если вы попытаетесь прогнать этот класс через модульное тестирование, то не сможете. Класс тесно взаимосвязан со средой приложения и базой данных.
Давайте с самого начала не будем усложнять работу с тем, что требуется классу. Просто в первую очередь потребуем, чтобы объект PDO был внедрён в класс.
class AwesomeClass
{
private $dbConnection;
public function __construct(\PDO $dbConnection)
{
$this->dbConnection = $dbConnection;
}
public function doSomethingAwesome()
{
// Make magic happen with $this->dbConnection
}
}
Получилось гораздо чище и проще для понимания, меньше вероятность ошибок. Благодаря подсказке типов и внедрению зависимостей метод объявляет именно то, что ему нужно для выполнения задачи, и получает необходимое без вызова из себя внешней зависимости. А когда речь пойдёт о модульном тестировании, мы окажемся готовы к моделированию подключения к БД и спокойно пройдём тест.
Контейнер внедрения зависимости — это инструмент, в который вы обёртываете всё ваше приложение ради создания и внедрения этих самых зависимостей. Контейнер не является необходимым, но значительно облегчает жизнь по мере роста и усложнения вашего приложения.
Мы воспользуемся самым популярным DI-контейнером для PHP с изобретательным названием PHP-DI. (Надо отметить, что в его документации внедрение зависимостей описано иначе, и кому-то так будет понятнее.)
Контейнер внедрения зависимостей
Поскольку мы настроили Composer, установка PHP-DI пройдёт практически безболезненно. Для этого снова обратимся к командной строке:
composer require php-di/php-di
Обновите public/index.php
для конфигурирования и сборки контейнера.
// ...
require_once dirname(__DIR__) . '/vendor/autoload.php';
$containerBuilder = new \DI\ContainerBuilder();
$containerBuilder->useAutowiring(false);
$containerBuilder->useAnnotations(false);
$containerBuilder->addDefinitions([
\ExampleApp\HelloWorld::class => \DI\create(\ExampleApp\HelloWorld::class)
]);
$container = $containerBuilder->build();
$helloWorld = $container->get(\ExampleApp\HelloWorld::class);
$helloWorld->announce();
Ничего особенного пока не произошло. Это лишь простой пример, где всё необходимое помещено в один файл для удобства наблюдения.
Мы конфигурируем контейнер, поэтому нужно явно объявить зависимости (а не использовать автоматическое внедрение или аннотации) и извлечь из контейнера объект HelloWorld
.
Заметка на полях: автоматическое внедрение зависимостей может быть полезной фичей в начале создания приложения, но в дальнейшем оно усложняет сопровождение, поскольку зависимости остаются относительно скрытыми. К тому же возможно, что через несколько лет другой разработчик подключит какую-нибудь библиотеку, и в результате несколько библиотек будут реализовывать один интерфейс. Это сломает автоматическое внедрение зависимостей и приведёт к непредсказуемому потоку багов. Разработчик, внёсший изменение, может их вообще не заметить.
Давайте ещё больше всё упростим, импортировав пространства имён там, где это возможно.
<?php
declare(strict_types=1);
use DI\ContainerBuilder;
use ExampleApp\HelloWorld;
use function DI\create;
require_once dirname(__DIR__) . '/vendor/autoload.php';
$containerBuilder = new ContainerBuilder();
$containerBuilder->useAutowiring(false);
$containerBuilder->useAnnotations(false);
$containerBuilder->addDefinitions([
HelloWorld::class => create(HelloWorld::class)
]);
$container = $containerBuilder->build();
$helloWorld = $container->get(HelloWorld::class);
$helloWorld->announce();
Пока что выглядит всё так, словно мы устроили суматоху ради выполнения того, что уже делали раньше.
Не беспокойтесь, контейнер нам пригодится, когда добавим несколько других инструментов, помогающих передавать запросы напрямую через приложение. Эти инструменты будут использовать контейнер для загрузки правильных классов по мере необходимости.
https://kevinsmith.io/modern-php-without-a-framework-middleware
Middleware
Если представить приложение в виде луковицы, в которой запросы идут снаружи к центру, а ответы в обратном направлении, то middleware — это каждый слой луковицы, который получает запросы, вероятно, что-то делает с ответами и передаёт их в нижний слой либо генерирует ответ и отправляет в верхний слой. Такое случается, если промежуточный слой проверяет запросы на соответствие каким-то условиям вроде запроса несуществующего пути.
Если запрос проходит до конца, приложение обработает его и превратит в ответ. После этого каждый промежуточный слой в обратном порядке будет получать ответ, возможно, модифицировать его и передавать следующему слою.
Варианты использования промежуточных слоев:
- Отладка проблем при разработке.
- Постепенная обработка исключений в production.
- Ограничение частоты входящих запросов.
- Ответы на запросы неподдерживаемых медиатипов.
- Обработка CORS.
- Маршрутизация запросов в соответствующие обрабатывающие классы.
Промежуточный слой — это единственный способ реализации инструментов для обработки всех этих ситуаций? Вовсе нет. Но реализации middleware позволяют сделать цикл запрос/ответ гораздо понятнее, что сильно упростит отладку и ускорит разработку.
Мы воспользуемся промежуточным слоем для последнего сценария: маршрутизации.
Маршрутизация
Маршрутизатор применяет информацию из запроса, чтобы понять, какой класс должен его обработать (например, URI /products/purple-dress/medium
должен быть обработан с помощью класса ProductDetails::class
с передаваемыми в качестве аргументов purple-dress
и medium
).
Наше приложение будет использовать популярный маршрутизатор FastRoute через реализацию промежуточного слоя, совместимого с PSR-15.
Диспетчер middleware
Чтобы наше приложение стало работать с каким-либо промежуточным слоем, нам понадобится диспетчер.
PSR-15 — это стандарт, определяющий интерфейсы для middleware и диспетчеров (в спецификации они называются «обработчики запросов»), обеспечивающий взаимосовместимость широкого спектра решений. Нам лишь нужно выбрать диспетчер, совместимый с PSR-15, и он будет работать с любым совместимым middleware.
В качестве диспетчера установим Relay.
composer require relay/relay:2.x@dev
А поскольку спецификация PSR-15 подразумевает, чтобы реализация промежуточного слоя передавала HTTP-сообщения, совместимые с PSR-7, мы воспользуемся Zend Diactoros.
composer require zendframework/zend-diactoros
Подготовим Relay к приёму промежуточных слоев.
// ...
use DI\ContainerBuilder;
use ExampleApp\HelloWorld;
use Relay\Relay;
use Zend\Diactoros\ServerRequestFactory;
use function DI\create;
// ...
$container = $containerBuilder->build();
$middlewareQueue = [];
$requestHandler = new Relay($middlewareQueue);
$requestHandler->handle(ServerRequestFactory::fromGlobals());
В строке 16 мы с помощью ServerRequestFactory::fromGlobals()
будем собирать всю информацию, необходимую для создания нового запроса и передачи его Relay
. Здесь запрос попадает в стек промежуточных слоев.
Теперь добавим FastRoute
и обработчика запросов (FastRoute
определяет, валиден ли запрос и может ли он быть обработан нашим приложением, а обработчик запросов передаёт запрос тому обработчику, что сконфигурирован для этого маршрута).
composer require middlewares/fast-route middlewares/request-handler
А теперь определим маршрут для класса обработчика Hello, world!.. Здесь мы воспользуемся маршрутом /hello
, чтобы продемонстрировать возможность использования маршрута, отличающегося от базового URI.
// ...
use DI\ContainerBuilder;
use ExampleApp\HelloWorld;
use FastRoute\RouteCollector;
use Middlewares\FastRoute;
use Middlewares\RequestHandler;
use Relay\Relay;
use Zend\Diactoros\ServerRequestFactory;
use function DI\create;
use function FastRoute\simpleDispatcher;
// ...
$container = $containerBuilder->build();
$routes = simpleDispatcher(function (RouteCollector $r) {
$r->get('/hello', HelloWorld::class);
});
$middlewareQueue[] = new FastRoute($routes);
$middlewareQueue[] = new RequestHandler();
$requestHandler = new Relay($middlewareQueue);
$requestHandler->handle(ServerRequestFactory::fromGlobals());
Чтобы всё заработало, нужно обновить HelloWorld
, сделав его вызываемым классом, то есть чтобы этот класс можно было вызвать как функцию.
// ...
class HelloWorld
{
public function __invoke(): void
{
echo 'Hello, autoloaded world!';
exit;
}
}
Обратите внимание на добавленный exit;
в магическом методе __invoke()
. Скоро вы поймёте, к чему это.
Теперь откройте http://localhost:8080/hello и наслаждайтесь своим успехом!
Клей, который всё скрепляет вместе
Проницательный читатель заметит, что DI-контейнер, несмотря на все трудности его конфигурирования и сборки, на самом деле ничего не делает. Диспетчер и промежуточное ПО могут работать и без контейнера.
Так зачем он нужен?
А что, если — как это почти всегда бывает в реальных приложениях — у класса HelloWorld
есть зависимость?
Давайте её добавим и посмотрим, что произойдёт.
// ...
class HelloWorld
{
private $foo;
public function __construct(string $foo)
{
$this->foo = $foo;
}
public function __invoke(): void
{
echo "Hello, {$this->foo} world!";
exit;
}
}
Перезагрузим браузер, и...
Ой.
Видим ArgumentCountError
.
Это происходит потому, что для функционирования HelloWorld
требуется при его создании внедрить строковое значение, а у нас это повисло в воздухе. И здесь на помощь приходит контейнер.
Давайте определим зависимость в контейнере и передадим его в RequestHandler
для разрешения.
// ...
use Zend\Diactoros\ServerRequestFactory;
use function DI\create;
use function DI\get;
use function FastRoute\simpleDispatcher;
// ...
$containerBuilder->addDefinitions([
HelloWorld::class => create(HelloWorld::class)
->constructor(get('Foo')),
'Foo' => 'bar'
]);
$container = $containerBuilder->build();
// ...
$middlewareQueue[] = new FastRoute($routes);
$middlewareQueue[] = new RequestHandler($container);
$requestHandler = new Relay($middlewareQueue);
$requestHandler->handle(ServerRequestFactory::fromGlobals());
Вуаля! При перезагрузке браузера вы должны увидеть Hello, bar world!.
Правильная отправка ответов
Помните, я упомянул о выражении exit
в HelloWorld
?
Это простой способ удостовериться, что мы получили простой ответ, но всё же это не лучший способ отправки выходных данных в браузер. Такой грубый подход заставляет HelloWorld
делать лишнюю работу по отдаче отчетов — а этим должен заниматься другой класс, — что слишком усложняет отправку заголовков и кодов статуса, а также приводит к закрытию приложения, не давая шансов запуститься промежуточному ПО, идущему после HelloWorld
.
Помните, что каждый промежуточный слой имеет возможность модифицировать запрос по пути в приложение, а также (в обратном порядке) модифицировать ответ по пути из приложения. В дополнение к стандартному интерфейсу для Request PSR-7
определяет структуру ещё одного HTTP-сообщения, которое будет нам полезно на обратной ветке цикла: Response
. Если хотите, можете почитать подробнее о HTTP-сообщениях и о том, чем хороши стандарты PSR-7 Request и Response.
Обновим HelloWorld
для возвращения Response
.
// ...
namespace ExampleApp;
use Psr\Http\Message\ResponseInterface;
class HelloWorld
{
private $foo;
private $response;
public function __construct(
string $foo,
ResponseInterface $response
) {
$this->foo = $foo;
$this->response = $response;
}
public function __invoke(): ResponseInterface
{
$response = $this->response->withHeader('Content-Type', 'text/html');
$response->getBody()
->write("<html><head></head><body>Hello, {$this->foo} world!</body></html>");
return $response;
}
}
Обновим определение контейнера, чтоб HelloWorld
предоставлялся со свежим объектом Response
.
// ...
use Middlewares\RequestHandler;
use Relay\Relay;
use Zend\Diactoros\Response;
use Zend\Diactoros\ServerRequestFactory;
use function DI\create;
// ...
$containerBuilder->addDefinitions([
HelloWorld::class => create(HelloWorld::class)
->constructor(get('Foo'), get('Response')),
'Foo' => 'bar',
'Response' => function() {
return new Response();
},
]);
$container = $containerBuilder->build();
// ...
Если мы сейчас обновим страницу, то получим пустой экран. Приложение возвращает из диспетчера промежуточных слоев правильный объект Response
, а потом… что?
Просто ничего с ним не делает.
Нам нужен ещё один инструмент: эмиттер. Он находится между приложением и веб-сервером (Apache, nginx и т. д.) и отправляет ваш ответ клиенту, сгенерировавшему запрос. Эмиттер просто берёт объект Response и преобразует в инструкции, доступные для понимания серверным API.
Хорошие новости! Пакет Zend Diactoros
, который мы уже используем для управления запросами, включает в себя эмиттер для ответов PSR-7.
Для простоты примера мы используем здесь очень простой эмиттер. Хотя он может быть гораздо сложнее, но в случае больших загрузок реальное приложение должно быть сконфигурировано для автоматического использования потокового эмиттера. Это хорошо описано в блоге Zend.
Обновим public/index.php
для получения Response
от диспетчера и передачи в эмиттер.
// ...
use Relay\Relay;
use Zend\Diactoros\Response;
use Zend\Diactoros\Response\SapiEmitter;
use Zend\Diactoros\ServerRequestFactory;
use function DI\create;
// ...
$requestHandler = new Relay($middlewareQueue);
$response = $requestHandler->handle(ServerRequestFactory::fromGlobals());
$emitter = new SapiEmitter();
return $emitter->emit($response);
Перезагрузим страницу — мы снова в деле! Пришло время для более надёжной обработки ответов.
В строке 15 заканчивается цикл запрос/ответ и вступает в работу веб-сервер.
Завершение
С помощью 44 строк кода и нескольких широко используемых, тщательно протестированных, надёжных, взаимодействующих друг с другом компонентов мы реализовали программу bootstrap
современного PHP-приложения. Он совместим со стандартами PSR-4, PSR-7, PSR-11 и PSR-15, поэтому вам доступен широкий спектр реализаций HTTP-сообщений, DI-контейнеров, middleware и диспетчеров.
Мы углубились в некоторые технологии и аргументацию, но я надеюсь, вам очевидна простота программы начальной загрузки нового приложения без сопутствующего хлама фреймворка. Также надеюсь, что вы теперь лучше готовы к применению этих технологий в существующих приложениях.
Использованное в статье приложение лежит в репозитории, можете свободно форкать и скачивать.
Если хотите почитать о качественных несвязанных пакетах, то очень рекомендую ознакомиться с Aura, The League of Extraordinary Packages, компонентами Symfony, компонентами Zend Framework, заточенными под безопасность библиотеками Paragon Initiative и списком совместимого с PSR-15 middlleware.
Если воспользуетесь этим кодом в production
, то, вероятно, вам понадобится вынести маршруты и определения контейнера в отдельные файлы, чтобы легче было сопровождать их по мере усложнения проекта. Также рекомендую реализовать EmitterStack для «умной» обработки скачиваний файлов и прочих больших ответов.
Комментарии (121)
eandr_67
27.03.2018 20:40+1Вместо того, чтобы использовать готовый и уже собранный [микро]фреймворк, автор собрали собственный микрофреймворк из готовых компонентов. Так что «без фреймворков» — ложь.
В отличие от этого поверхностного «воткните штекер А в гнездо Б», у Дмитрия Елисеева идёт детальный разбор того, как каждый компонент работает и почему это устроено именно так.Mendel
27.03.2018 21:09Ну так задача была — напишем сами, и все сами поймем. В статье особо ничего и не написано — придется разбираться самим. Так что все правильно)
Loki3000
28.03.2018 09:49На мой взгляд, в статье посыл правильный, хотя и не очень удачно донесенный: набор компонентов должен отталкиваться от задач. Компоненты вполне могут быть из одного фреймворка, но нужно понимание того, для чего они используются. Конкретно в приведенном примере, чтобы вывести «Hello world» нам не нужна ORM, QueryBuilder и еще многое из того ливера, который почти в любом фреймворке будет у нас из коробки.
medvoodoo
29.03.2018 15:23Я уже очень далек от PHP, но в свое время(когда только появился композер) меня дико напрягало:
1. Разная философия пакетов (ларавель использующий колбек вызов свифт мейлера, когда мне нужно было на лету что-то модифицировать в отправке).
2. Пакеты, не заточенные под композер, в которых настройки прошиты где-то в их папке и вынести нормально эти настройки не было возможности.
Может быть сейчас все изменилось, но все-равно не думаю, что правильно собирать такого Франкенштейна, ведь плюс любого хорошего фреймворка в однотипном написании всех его компонентов.Loki3000
29.03.2018 16:05Какие проблемы — берите компоненты из одного фреймворка. Просто если вам нужен один-два компонента, зачем тащить фреймворк целиком?
medvoodoo
29.03.2018 18:09А из каких фреймворков сейчас можно нормально брать компоненты чтобы писать с нуля, и, я реально отстал от жизни PHP(больше 4 лет не касался), какие компоненты каких фреймворков имеет смысл сочетать? Вот из этих habrahabr.ru/company/nixsolutions/blog/329718
vlreshet
29.03.2018 19:26Из Symfony, и, в принципе, наверное можно и из Zend. Тот же laravel более чем наполовину состоит из компонентов Symfony
medvoodoo
29.03.2018 20:37двушка симфы изначально так и писалась, из зенда на уровне 1.х можно было брать либы. из ларавеля и из юи брать не имеет смысла из-за зависимостей и уникальности, я правильно понимаю? Тогда зачем изобретать надуманные кейсы? Как и в js и pythone есть независимые либы, которые независимо и подключаются(свифт), а плагины(пакеты) писались и пишутся под конкретный фреймворк. Я скажу про питон, что если мне нужно что-то простое, я возьму бутылку, и точно не буду к ней использовать джанго пакеты, так же как в реакте не буду пользовать ангулар пакеты.
VolCh
30.03.2018 08:33В экосистеме Symfony есть три основных типа либ: бандлы, бриджи и компоненты. Компоненты — самодостаточные либы, не зависящие от фреймворка, которые можно брать и использовать практически в любом приложении. Бриджи обычно — низкоуровневые адаптеры над либами, прежде всего сторонними, приводящие их к Symfony-way API/UI и(или) обратно (родные компоненты Symfony по понятным причинам обычно в них не нуждаются). Бандлы — обычно тесно интегрированы с фреймворком, в том числе с девтулсами, активно взаимодействуют с событийной моделью Symfony, с флоу пути запроса-ответа. часто имеют собственный веб-UI вплоть до предоставления единственного UI приложения. Собственно сам фреймворк — лишь бандл. С другой стороны, нередко они лишь тонкие адаптеры к компоненту/бриджу, например, просто регистрирующие сервисы в контейнере и конфигурирующие их в Symfony-way. С последними релизами Symfony (3.4 и 4.0 прежде всего) нужды в таких бандлах стало значительно меньше, регистрацию и конфигурирование можно делать автоматически, лишь "натравив" контейнер на нужную папочку.
Бандлы — практически полнофункциональные, пускай и узкоспециализированные, приложения, сильно зависят от фреймворка, очень часто являются пакетами тесной интеграции компонентов или сторонних библиотек в фреймворк. Когда достаточно простые обертки, когда заметно сложнее собственно оборачиваемой либы (полноценное внедрение в девтулсы, например) или имеют свой собственный UI типа бандла для RAD админок. Собственно сам фреймворк — это тоже бандл.
medvoodoo
30.03.2018 10:08Огромное спасибо за информацию. Только получается, мы не отказываемся от фреймворка, а берем symfony. Или берем любой другой фреймворк и подключаем симфони компоненты.
ionicman
27.03.2018 20:41+1Обойдемся без фреймворка, просто возьмем:
- Composer
- PHP-DI
- Zend Diactoros
Готово — мы вывели «Hello, world»!
Ага, современный бэк — бессмысленный и беспощадный :D
Лучше уж готовый фреймворк, чем такой борщ из библиотек (которые и не библиотеки на самом деле а микро-фреймворки). И преемственность выше и код понятней и обслуживать проще и документация по всем компонентам сразу.Mendel
27.03.2018 21:14Для работы да. А для изучения?
Нет, я конечно понимаю что здесь чисто «как нарисовать сову», но тем не менее…
Хотя да, по здравости если подумать. Добавил в закладки чисто потому что «потом когда-то решу причухать свой фреймворк и выпустить в паблик, тогда загляну сюда, поменяю часть своих велосипедов на что-то более PSRистое». А так то наверняка бы половину не понял в статье, если бы все это не знал раньше.banderos120
28.03.2018 09:53Ну, насколько я могу видеть в статье написано: «следующий проект начниете писать без фреймворков», что как-то идет в разрез с простым обучением, а намекает на работу.
VolCh
27.03.2018 21:44Что из приведенного отвечает определению микрофреймворка? Какое будет ваше определение? Где грань между фреймворком и вызовом переданных заранее колбеков?
velvetcat
27.03.2018 22:32+1которые и не библиотеки на самом деле а микро-фреймворки
Нет, это именно библиотеки. А Вы не понимаете разницу между библиотекой и фреймворком.
Статья — норм, заголовок — вполне точен.
И хотя по сути автор описывает, как создать свой микрофреймворк из стандартных библиотек, это нормально, так как любое более-менее структурированное приложение держится на некоем каркасе, готовом или самописном.
ionicman
28.03.2018 07:21+1А Вы не понимаете разницу между библиотекой и фреймворком.
Для меня отличие библиотеки от фреймворка в том, что библиотека выполняет четко только одну задачу, микрофреймворк — задачу и смежные с ней (близкие по функционалу).
На примере композера — грубо — он выполняет и проверку зависимостей и автозагрузку классов и установку модулей — для меня это — микрофреймфорк. Т.к. все эти задачи, хоть и близкие по функционалу, все-таки различны.
Ноу проблем — укажите мне, где я ошибаюсь.
Но на самом деле пост то не про это был, а про то, что человек слепил свой собственный фреймворк из кучи модулей и утверждал, что обошелся без фреймворка.
А на самом деле он слепил свой собственный неуклюжий фреймворк, за бортом осталась шаблонизация (а без нее в современном вебе никак), нормальная авторизация, настройки, хранилище и т.д. — когда он все это прилепит — у него и получится обычный фреймворк, только зависящий от кучи разных библиотек, не протестированных на четкую работу вместе, отсутствие единого вектора в развитии (библиотеки будут развиваться отдельно и по разным векторам, так как они все от разных разработчиков), отсутствие единой документации и единого хранилища и т.д.
При этом все, что указывалось как недостаток обычных фреймворков будет точно также.
Тогда смысл? :DMendel
28.03.2018 08:43Смысл — поиграться. Другого смысла нет. Ну или как бутстрап для своего фреймворка, если уж всерьез писать. Если бы в статье было чуть подробнее и понятнее для новичка, и были бы все базовые понятие/PSRы реализованы/прилинкованы, то статья была бы действительно полезной. А так это пока лишь заготовка.
arturpanteleev
28.03.2018 12:02+1«Главное отличие библиотек от фреймворков в том, что фреймворк запускает ваш код, и, в общем случае, контролирует свое собственное окружение; в то время, как библиотека – это нечто, что вы используете из своего кода, контролируя свое окружение самостоятельно»
Т.е если упрощать, то фреймворк управляет кодом приложения, а при использовании библиотек, код самого приложения управляет библиотекой. Под спойлером картинка.
Схемаvelvetcat
28.03.2018 12:34микрофреймворк — задачу и смежные с ней
Нет, смысл совсем не в размере, охвате и пр.
Суть в направлении контроля. Фреймворк вызывает Вас. Вы вызываете библиотеки.
А на самом деле он слепил свой собственный неуклюжий фреймворк, за бортом осталась шаблонизация… не протестированных на четкую работу вместе
Почему это он неуклюжий? Зачем мне шаблонизация, если у меня строго JSON API? Суть — с введением PSR можно самому собрать собственный фреймворк, делающий ровно то, что нужно и ничего больше, из кода разных производителей.
ionicman
28.03.2018 12:54Интересное определение, а если библиотека вызывает Ваш callback (любой eventer) — она сразу же становится фреймворком?
Тем более разговор был про микрофреймворки, не так ли?
Можно ссылку почитать такое определение для микрофреймворков?
Ибо ИМХО push/pull — это модель работы, но ни как не определение.
Единственное, с чем согласен — что фреймворк (не микрофреймворк) всегда идет со своим окружением, которое он постоянно поддерживает в актуальном состоянии — на то он и «каркас».khim
28.03.2018 17:18Интересное определение, а если библиотека вызывает Ваш callback (любой eventer) — она сразу же становится фреймворком?
Я бы сказал что всё зависит от «масштабов бедствия»: если подавляющее большинсво кода, использующего библиотеку не является кодом callback'ов, то, конечно нет. От того, что вы callback на три строки в qsort передали libc не станет фреймворком.
А вот если у вас большая часть приложения, общающаяся с библиотекой и состоит из этих callback'ов… тогда да. Скажем GTK обычно позиционируется как библиотека виджетов, но на практике — это скорее фреймворк.
Хотя да, конечно, бывают и пограничные случаи…
Aliance
28.03.2018 21:41А на самом деле он слепил свой собственный неуклюжий фреймворк,… у него и получится обычный фреймворк, только зависящий от кучи разных библиотек, не протестированных на четкую работу вместе
В этом-то и идея PSRов, что реализуя интерфейс, не нужно тестировать взаимодействие, потому что оно гарантировано контрактом и тестами самой реализации.
alexdevid
27.03.2018 21:23Когда-то я так пробовал делать, в итоге у меня получился Symfony процентов на 70.
После этого решил, что не зачем выпендриваться — минусов больше чем плюсов.
но для обучения полезно, спору ет
VolCh
27.03.2018 21:47Для обучения я бы рекомендовал написать свои простые реализации для интерфейсов PSR для простых случаев и без оптимизаций, а не тянуть готовые, где тончайшие нюансы предусмотрены и до доль микросекунд код вылизан.
SbWereWolf
27.03.2018 22:00Спасибо за туториал, занятно. Общая идея понятна, наверное потому что я её уже знаю, а вот реализация вообще не понятна.
Спасибо за ссылки для дополнительного чтения.
Про луковицу в качестве метафоры для middleware не верное предложение, middleware как раз позволяет соединить несколько луковиц, независимых между собой, связанных только диспетчером.
Луковица подразумевает сильную связность внутри слоя и слабую связность между слоями, а самое главное уникальность функционала для каждого слоя.
В то время как одно middleware может проводить анализ данных, так и следующие middleware может проводить анализ тех же самых или уже изменённых данных, то есть слой анализа дублируется в разных middleware.
Про микро-фреймворки очень справедливое замечание, я знакомился со Slim-ом, он умеет две нужные вещи:
- роутинг,
- конвейнер мидлвэер
и больше ни чего, то есть весь функционал того что есть в статье. Свой велосипед делать не надо.
n1cebro
27.03.2018 22:51Осталось добавить сюда минимум то без чего не обойтись в минимальном приложении это ORM, миграции, валидацию, обработку шаблонов для email, отправку email, file storage и… получим то что Laravel предоставляет из коробки.
Без фреймворка хорошо писать только в целях саморазвития для своего личного проекта где вы будете сами это все поддерживать, но для коллективной разработки лучше всетаки использовать фреймворки так как они вносят свои стандарты построения приложений.VolCh
28.03.2018 00:49ORM полно однотипных и есть Doctrine. Валидаций куча, мейлеров популярных минимум 2 и всё это гвоздями друг к другу не прибито как в ларе. Стандартизация интерфейсов, низкая связанность и прочие современные тренды позволяют писать приложения, где, грубо говоря, хоть каждый день можно компоненты менять.
n1cebro
28.03.2018 01:19В чем вам легче будет разобратся в самописном коде, или в коде который был написан по стандартам фреймворка? А если код был написан не самым опытным программистом? Вам захотелось бы разбиратся в той архитектуре? А в случае с фреймворком если человек который писал код следовал стандартам, у вас уже будет более менее ясное представление о приложении. А насчет Laravel впервые слышу что там что то прибито гвоздями, наоборот при желании вы можете взять любой компонент и он будет работать отдельно от фреймворка.
SerafimArts
28.03.2018 01:38Конечно будет, но за собой потащит ещё половину ядра. Да и некоторая часть просто гвоздями прибита, например тот же шедулер или очереди. А пытаться миддлвари использовать отдельно от ларовского http (была у меня попытка прикрутить их к вебсокетным onMessage событиям) смерти подобно.
Ну т.е. скажем так. Некоторая часть фрейма отлично выдирается: Контейнер, саппорт, пагинатор и проч., а некоторую даже при всём желании адекватно не получится.n1cebro
28.03.2018 02:02Ну потащит окей, некоторые компоненты зависят от других и код реиспользуется. Это вроде как стандартный подход, любой компонент имеет какие-то свои зависимости.
SerafimArts
28.03.2018 12:50+1Да то что тащит — это мелочи, хотя те же контракты при подключении саппорта не мало бесят. Особое удовольствие тут в том самом прибитии гвоздями и организации кода. Пытался я вытащить ларовские очереди и переложить их на доктрину. Это печальная история, должен я сказать.
n1cebro
28.03.2018 13:39Ну тогда можно не использовать компоненты Laravel не вижу тут проблемы :)
Мой месадж был о том что какраз эта прибитая гвоздями организация кода и позволяет командам писать код в пределах фреймворка который будет понятен всем. Когда при кастомном решении новому человеку пришедшему на проект надо будет вникать во все ньюансы самописного решения и думать как ему встроить что то новое чтобы не сломать старое.SerafimArts
28.03.2018 15:17Так никто не спорит. Я за ларку (и симфони) всеми руками и другими выпирающими частями тела. Я же коммент свой писал в качестве замечания на:
А насчет Laravel впервые слышу что там что то прибито гвоздями
да цитирование просто забыл. Теперь будете знать, что не всё в Багдаде спокойно, хотя казалось бы… =)
greabock
28.03.2018 17:16Вот не надо, в ларе гвоздями прибиты три вещи: контейнер, система событий и роутер. Всё остальное, включая упомянутый шедулер и очереди, легко (ну ладно, не очень легко) разруливается написанием своего драйвера.
P.S. ну и да, доп пакеты типа пасспорта, довольно жестко завязаны на ёлку.
VolCh
28.03.2018 20:48Стандарты стандартам рознь. И в целом как раз по стандартам какого-то фреймворка написанный код сильно завязан обычно на этот фреймворк, разбираясь с приложением на незнакомом фреймворки очень значительную часть времени будешь тратить на изучение фреймворка, потому что, например по его стандартам принято создавать и обрабатывать формы по метаинформации из класса сущности. Он позволяет разделять их, но по стандартам не принято дублировать информацию, совпадающую на 99% по содержанию в 99% случаев.
Sabubu
27.03.2018 22:51У меня конечно осталось ощущение переусложненности. Ну например, зачем делать объект "вызываемым" через invoke, когда можно сделать обычный, немагический метод? Ради чего? Такое ощущение, что они используют invoke просто чтобы он был.
Насчет DI контейнера — по моему, Pimple проще. Там определение сервисов делается просто через анонимные функции, без этих громоздких конструкций \DI\create(Some::class).
Зачем нужно тут middleware? По моему, проще роутер просто вызывать напрямую и обойтись тем самым без библиотеки Relay. Или целью автора было использовать очередной PSR?
А так, конечно, я не вижу ничего плохого. В той же Симфони мне например не нравится куча конфигов, модуль security и неявные вещи, вроде всяких обработчиков событий, из-за которых мы не можем легко проследить, как выполняется код, начиная с index.php.
dzsysop
27.03.2018 22:51Мне очень понравилась вводная часть. Я тоже сторонник сборки своего фреймыорка под проект. Но дальнейшая подача материала не стректурирована и не совсем понятно что и для чего мы делаем. Надеюсь, в скором времени накатать свой вариант статьи о сборке проекта из библиотек. Надеюсь у меня получится донести смысл такого подхода. Удачи!
lkoida
27.03.2018 22:51Очень даже неплохо, но как то все таки станно видеть как из готовых пакетов собирается собственно микрофреймворк. Как мне кажется, интереснее было бы в рамках обучающей статьи показать более детальный пример работы одной компоненты.
Klenov_s
27.03.2018 23:32Очень для меня сомнительно утверждение, что явно прописанные инклуды труднее понять и отследить, чем не прописанные в коде явно автозагрузки.
yvm
28.03.2018 00:06Очень правильно все, кто не понял, у меня для вас плохая новость… Идеальное приложение это комбинация слабосвязанных компонентов наиболее адекватных решаемой задаче. И есть фреймворки двигающиеся в этом направлении, например zend expressive. А symfony, zend и laravel… им спасибо за донорство компонентов )
VolCh
28.03.2018 00:52Где в Symfony сильная связанность?
Loki3000
28.03.2018 09:53+1Вот, кстати, тут у меня тоже есть претензии к symfony: несколько раз пытался использовать из него отдельные компоненты, а в результате у меня через зависимости вытаскивалась половина фреймворка. При таком положении вещей уж лучше его целиком использовать.
velvetcat
28.03.2018 12:45Где в Symfony сильная связанность
Ну на самом деле куча бандлов, идущие как стандартные, представляют собой месиво, гвоздями приколоченное к некоторым основным компонентам (типа Доктрины). Как будто сделано все, чтобы показать, что наличие интерфейсов еще не означает слабую связанность :).
Mendel
28.03.2018 08:50Эм… и вас не смущает что вы в одной фразе соединили обвинение перечисленных фреймворков в повышенной связности и «донорство компонентов»? Совсем-совсем не смущает?
pda0
28.03.2018 00:07+1А мне норм. По моему человек имел ввиду не то, что все должны бросить всё и каждый собирать свой велосипед, а то, что современное состояние php с composer и psr изменило понятие «фреймворк». Теперь это не закрытая инфраструктура, а просто набор взаимозаменяемых модулей. А фреймворки превратились в дистрибутивы Linux. И даже не Linux, а Debian/Ubuntu/Kubuntu/Lubuntu/Mint/etc… Т.е. нечно разное, но сильно взаимозаменяемое.
И относиться к этому надо именно так. И особенно разрабатывать код. И выбор фреймворка не что-то судьбоносное, а просто «мне нравится дефолтный выбор компонентов», «но если что — полностью перепахаю за денёк».VolCh
28.03.2018 01:05Справедливости ради, приложение нужно писать специально так, чтобы фреймворк сменить было «на день работы», то есть всё важное должно быть от фреймворка отделено, пускай компоненты из фреймворка использовать, но не пользоваться его магией, например, превращающую $_REQUEST в SQL запрос толком даже без описания схемы.
immaculate
28.03.2018 08:03Нет, писать свои велосипеды очень плохо. Сколько раз не приходилось сталкиваться с кодом, который был написан не на основе фреймворка или другого готового решения, это всегда был ужасный неподдерживаемый код.
Человек, не способный разобраться в чужом фреймворке, сделать на его основе высокоэффективное решение, не сможет создать свое решение, которое превосходит готовый фреймворк хоть в чем-то. Это аксиома.
Имеет смысла писать без фреймворка для того, чтобы понять, как оно все работает. На учебных проектах. Можно личный блог написать без фреймворка, или какой-нибудь другой игрушечный проект. Но ни в коем случае не production код.
Еще раз повторюсь: я еще ни разу не видел, чтобы человек, строящий велосипеды, смог сделать велосипед лучше существующего. Ни разу. Кроме тех, кто построил уже существующие фреймворки, но эти люди не начинали с нуля, у них уже был огромный опыт, и они понимали зачем строят фреймворк.
Кроме того, свой велосипед:
а) не будет иметь документации (в 99% случаев)
б) не будет иметь тестов (в 99% случаев)
в) будет использовать непонятные большинству сторонних разработчиков соглашения об именах, расположениях файлов, конфигурации, и т.д. и т.п.
г) не будет совместим с имеющимися батарейками для других фреймворков, всю дополнительную функциональность придется писать всегда с нуля
Я помню, как в одном проекте разработчик создал свой мета-фреймворк над фреймворком. Все функции и классы в нем назывались одной-двумя буквой для краткости. Например:
T -> render_to_response R -> redirect RV -> redirect_to_view E -> return HttpResponseError()
Это все было понятно ему, но когда он ушел из проекта, а на его место взяли меня, мне пришлось выучить около 20-30 этих сочетаний, причем не всегда они именовались логично. А дальше я столкнулся с тем, что он определил несколько модулей
utils
в разных пакетах, и в некоторых из них однобуквенные функции переопределялись, причем с немного иной семантикой… Тут начался ад, и я постоянно сталкивался с ошибками, так как мало того, что надо было вспоминать, что, например, обозначетRV('people-list')
. Надо было еще каждый раз смотреть в начало файла, чтобы посмотреть, из какого именно пакета это сокращение импортируется. Затем надо было вспомнить или посмотреть, что именно делаетRV
в данном пакете.
Через месяц мучений, я выкинул все это, и переписал на обычных вызовах методов фреймворка. Мне не сложно вместо
T
написатьrender_to_response
, тем более, что сейчас все редакторы и IDE поддерживают autocomplete или дополнение по образцу (Alt-/
в Idea). Зато абсолютно любому человеку, приходящему в проект, сразу понятно, что делает код.
TLDR: Изобретать велосипеды очень плохо, всегда получаются квадратные колеса. Всегда.
dmitriylanets
28.03.2018 09:11Тоже использую каркас , но как ни крути пришлось много допиливать: консоль, модули, шаблонизаторы и тд
qRoC
28.03.2018 09:25
zzzmmtt
28.03.2018 09:29PHP исполняет серверные приложения в цикле запрос/ответ. Всё взаимодействие с приложением — из браузера, командной строки или REST API — приходит в него в качестве запросов. При получении запроса приложение загружается, обрабатывает запрос и генерирует ответ, который передаётся обратно клиенту, а приложение закрывается. И так происходит при каждом обращении.
Не всегда, не нужно быть столь категоричным. Не забывайте, что php-приложение может запускаться БЕЗ запроса и при этом ничего не отправлять клиенту, запускается по крону, к примеру, собирает данные из нескольких баз, обрабатывает и складывает их в другую базу. И не стоит забывать, что php-скрипт вполне можно демонизировать, тогда оно завершаться будет только в исключительных случаях.
AlexPTS
28.03.2018 10:05Интерфейсы PSR позволили пойти путем стандартизации и переиспользования кода из коробки.
PSR-7 + PSR-15 позволили решать часть типовых задач отвязано от фреймворка X, на котором нравится писать. Самое ценное то, что благодаря стандартизации стало реально заменять реализации и использовать интерфейсы, без написания собственных адаптеров или интеграций. Как выше упоминалось, разработка простого приложения, действительно, сводится к скачиванию пакетов и выстраиванию цепочки их выполнения через PSR-15.
antonn
28.03.2018 10:33+2У меня есть для вас непростое задание. Когда в следующий раз начнёте новый проект, постарайтесь обойтись без PHP-фреймворка
Запросто, без проблем. Когда-то все сайты так и писались, и многие работают до сих пор. В чем тут сложности — не ясно. Сейчас кодить без Фреймворка — это что-то сложное и признак мастерства?
Когда вы впервые начали работать с PHP, то, вероятно, использовали выражения include или require для получения функциональности или конфигураций из других PHP-файлов.
…
Выход — автозагрузка. Это означает, что, когда вашему приложению нужно использовать какой-то класс, PHP знает, где его найти, и автоматически загружает в момент вызова
Огромное количество проблем в работе, совместимости и эксплуатации уязвимостей на моей памяти были связаны со словом «автоматически». А если не подгрузит «автоматически»? С инклудом хоть сразу видно будет.BupycNet
28.03.2018 10:54У автозагрузки есть еще интересный баг, если в коде есть проверки существования класса и т.д. и это все внутри цикла — это будет приводить к проверке file_exists на каждый вызов, а это файловая операция, которая может неплохо так замедлить весь цикл. Например внутри своего автолоадера я сразу впилил небольшой кэш проверок, на случай попытки подключения несуществующих классов. Но иногда подключая сторонние библиотеки ловлю там самостоятельные автолоадеры, которые таки делают постонные лишние запросы на проверку библиотек, которых нет.
Mendel
28.03.2018 11:07Любопытно. Не думал об этом.
Но мне что-то не приходит в голову кейс где будут множественные проверки существования класса, так чтобы не городить уж очень кривое что-то.
Проверка существования класса как по мне должна в случае его отсутствия объявлять ему замену. Других кейсов я не вижу.
Какие-то попытки автоматического внедрения зависимостей по цепочке воркараундов?
Ну это само по себе глупо. Ну в смысле цепочки делать. Пойди найди потом какое из умолчаний у тебя сработало.
Нет, возможно я что-то упускаю. Можете привести пример? Любопытно.BupycNet
28.03.2018 11:10Например вы в цикле вызываете другую библиотеку, которая в свою очередь при создании объекта таки определяет, какие есть библиотеки через проверку существования класса и " в случае его отсутствия объявлять ему замену. " как раз использует замену. Однако т.к. мы вызываем эту стороннюю библиотеку в цикле с разными параметрами — она постоянно проверяет существование классов. Если файлы находятся на медленном диске, или вообще подключаются через NFS — это может быть очень и очень долго.
Mendel
28.03.2018 11:15Так а что кешировать тогда если каждый раз новое ищется?
Или вы имеете ввиду не кеширование внутри сессии, а кеширование МЕЖДУ сессиями, типа сохраняем список несуществующих классов в файлик и при запуске автозагрузчика загружаем только этот файлик с отлупами?BupycNet
28.03.2018 11:40Static-кэш. Чтобы в рамках одной сессии не пробовать попытки подключения того, чего нет.
Akuma
28.03.2018 11:26Стоп. Но file_exists кешируется. И если вы в том же цикле не вызываете clearstatcache(), то все будет впорядке, пусть даже вы жуткий извращенец и код у вас лежит на NFS (я так делал — все работает).
Вы замеры делали? На сколько это реально тормозит систему?
А то мне это напоминает оптимизацию через одинарные кавычки.Mendel
28.03.2018 11:39Ну есть некоторые облачные хостеры (вернее платформы для оного) у которых файлы по сети и это да, превращается в проблему. И даже не совсем облачные а вроде банальный шаред заказывал, но потом тебе рассказывают про облака…
Я раньше пытался бороться с этим, даже удачно. Но сейчас решил что дешевле сменить хостера.BupycNet
28.03.2018 11:41Лишние операции даже к очень быстрой файловой системе могут быть медленнее, чем к локальному Redis. Причем ФС может быть загружена конкурирующими запросами.
BupycNet
28.03.2018 11:39Может у вас кэшировался — у меня вот нет. У меня быстрые скрипты без фреймворков — там весь скрипт менее чем за 1мс выполняется, причем большую часть занимают запросы к БД. Так вот xhprof явно указывал что выполнялось много лишних файловых операций проверки file_exists из автолоадера.
Сейчас точно не вспомню, но мне кажется в phpmailer была как раз проблема у меня в консюмере, что автолоадер там с ума сходил.Akuma
28.03.2018 11:43Возможно как-то зависит от настроек системы. Но я специально проверял эту фичу (file_exists, is_file, is_dir) — и оно правда кешируется. У меня даже есть кейсы сброса этого кеша и там без clearstatcache() никак.
Не знаю на счет кеша в разных сессиях (не проверял), но в пределах одной у меня он всегда работал.
nitso
28.03.2018 14:24В контексте composer, например, есть несколько
уровнейвариантов оптимизации автозагрузки: https://getcomposer.org/doc/articles/autoloader-optimization.md. Этот же механизм позволяет легко отлаживать проблемы, которые могут быть вызваны некорректной автозагрузкой классов.
Mendel
28.03.2018 11:01Сейчас кодить без Фреймворка — это что-то сложное и признак мастерства?
А не получается без фреймворка.
В принципе не получается.
Один раз вкусил и всё. Без него уже не можешь. Как наркотики.
Сколько раз я уже начинал «простенький проект, будем без фреймворка делать». Какой-то MVP-одностраничник, или просто расколупать шаблон перед натягиванием (большой шаблон, типа AdminLTE, но все равно) — чисто разобраться во внутренностях, порезать на куски…
Потом вдруг очнешься посередине, а у тебя уже микрофреймворк написан.
Минимальный шаблонизатор на 20 LOC, минимальный функционал мультиланг на 50 LOC, ассетсы на 20 LOC, сахарная функциональщина ко всему этому на пару дюжин строк, а дальше уже просто не можешь удержаться и не сделать роутер на дюжину строк, и потом в это все внести хоть в структуру MVC. И всё. По сути это уже не «без фреймворка». а пусть и совсем крошечный и не полноценный, но фрейиворк.antonn
28.03.2018 11:14+1Один раз вкусил и всё. Без него уже не можешь. Как наркотики.
Значит у меня иммунитет на такие наркотики.
Уж сколько на шарпе пишу, на яве, а вот пхп в несложных проектах просто отрада за возможность быстро и просто написать несложный сайт в процедурном стиле. Максимум для шаблонизатора накидать класс, да и тут можно обойтись. Просто сравните самый первый блок кода в этой статье, и ту портянку к которой мы пришли в конце — они выдают один и тот же результат, но во втором случае мы навернули на порядок больше строк, в которых потенциально может скрываться ошибка (про производительность вообще молчу). Большинство сайтов, при всем при этом, представляют собой (функционально) как раз тот самый первый блок, но «наркоманы» от Фреймворков превращают их в многострочных мастодонтов, зато там все внутри «универсально и автоматически». Потом дают тебе такой проект на фикс и правки, и начинаешь разматывать все эти ненужные цепочки выискивая где-же оно «автоматически» не сработало, чтобы потом упереться в ограничения архитектуры используемого фреймворка.Mendel
28.03.2018 11:35Ну я не говорю про использование монструозных библиотек.
Но банальный DRY вынуждает писать шаблонизатор. Иначе будет капец.
Потом еще что-то, еще что-то и просыпаешься с готовым фреймворком.
Буквально пару десятков разных страниц, пару дюжин UI-компонент (часто со своими зависимостями) и всё, приехали. Разобраться в портянке невозможно.
CSS на полсотни килобайт листать для каждой правки. Потом потерянный мертвый код, ад зависимостей (всякие js/css библиотеки… кому они нужны? Может я уже удалил это давно? А что это за css-класс такой? Где он используется?).
Начинаешь таки упорядочивать.
Хоть минимально чтобы css/js и подгрузка внешних файлов для них лежали в одном месте с шаблоном который их использует. И компилировались на лету.
А значит уже минимальный ассет-менеджер.
Потом понимаешь что все равно придется делать двуязычную версию. Да и клиент захочет править всякие строки отдельно, не заглядывая в код.
Выносим все строки в json-ы к одноименным шаблонам.
Готов еще один класс в наш фреймворк.
Нет, нет, я не буду писать роутер. Нет, у меня только одна страница всего. Ну хорошо две, языки еще разные, но я могу это одной строчкой написать.
Ну ок, есть еще чуть другой интерфейс для админа, но что ради этого роутер писать? Не буду! Статические файлы? Кишки «фреймворка» спрятать в хтаксесс? Все равно не буду. Черт, еще форма фидбека и страница ЧАВО. Ну хорошо, хорошо, пять строчек роутера это не фреймворк…
Контроллеры? Ну блин, есть же контроллеры в ангуляровской части! Ну ладно, ладно, напишу, а то будет как с роутером.
Черт, как все-таки удобно когда формы генерятся из модели автоматом. И валидация…
Даже и не думай! Не думай я тебе сказал!
Вот как-то так было у меня в голове крайнюю неделю.
И то что вышло в итоге — уже микроскопический, но фреймворк.
Ну не получается у меня без фреймворков. Не получается.
zzzmmtt
28.03.2018 11:43Заголовок спойлераVolCh
28.03.2018 21:32В большинстве сайтов есть какая-никакая работа с СУБД, есть формы (в том числе с файлами), есть валидация, есть защита от инъекций, есть какой-то роутинг (пускай и на уровне php-файлов), есть конфиги, часто есть аутентификация и авторизация, нередко есть отправка почты и скрипты CLI (например для крноджобов). Кэширование. Это только навскидку.
antonn
29.03.2018 12:26+1Все это неоднократно реализовывалось мной без каких либо фраемворков, даже классов по минимуму, процедурный стиль, написано в обычном notepad.exe (я серьезно, никаких подсветок синтаксиса, автокомплита, автоформата и прочего), только глобальные переменные, процедуры и 1 необходимый класс (phpmailer). Спустя 10 лет я спокойно нашел где мне пофиксить импорт rss в кишках сайта.
Личные сайты в профиле — в этом стиле и сделаны (там и БД, и юзеры/профили, форм навалом, файлы и превьюшки, защита от XSS, работа с почтой, загрузки файлов, своя подсветка BB-codes, скрипты для крона, капча, форум/гостевая/чат; верстка на железобетонных таблицах). И код внутри примитивный и простой, для фикса не надо разбираться с фреймворками, который каждые пару лет меняются и помирают, в которых находят дыры и надо держать руку «на пульсе» чтобы сайты на их основе не подвергать риску. Очень много людей играют в «ООП ради ООП» с фреймворками и палят из пушки по воробьям.Mendel
29.03.2018 12:36не надо разбираться с фреймворками, который каждые пару лет меняются и помирают, в которых находят дыры и надо держать руку «на пульсе» чтобы сайты на их основе не подвергать риску
Этому явлению есть давно устоявшееся название: «Неуловимый Джо» называется.
Есть такая известная атака из класса «человек посередине». Подобную уязвимость находили во многих фреймворках. У вас не находили.
Атака заключается в уводе сессии или просто XSRF вскрывая токен безопасности манипулируя юзерконтентом и анализируя степень сжатия страницы.
Как у вас с этим? Наверняка продумали...)antonn
29.03.2018 14:19У меня SSID генерится на основе useragent+remote_ip (и немного соли, но не суть). Если другой пользователь сможет веб-серверу показать себя под IP другого человека (например из его сети с NAT) и передаст его useragent + поле соли в куке (генерится при аутентификации), то сайт разумеется будет считать что это зашел владелец сессии. Никакие действия через GET не выполняются, отправив POST и обманув веб-сервер можно выполнить что угодно в рамках привилегий пользователя.
Насчет «неуловимого Джо» не совсем уверен, логи постоянно пестрят попытками XSS и sql-inj через запросы, но это автоматы перебора, люди сдаются раньше.Mendel
29.03.2018 20:42+1Ну т.е. ваш сайт в принципе спокойно вскрывается «человеком посередине», даже при сертификатах с А+. Прекрасно. Уровень среднего фреймворка годов этак 2012-2013. Да, да, 2013. Я правильно угадал. Тот же BREACH например стал общеизвестным именно в этом году, и именно тогда большинство фреймворков от нее закрылись. Некоторые чуть позже.
Ну и я не стану придираться к «У меня SSID генерится на основе useragent+remote_ip (и немного соли, но не суть)». Предположим что вы просто неудачно выразились, а имели ввиду нечто иное.
У меня несколько иной чем у вас уровень проработки подобных вопросов, но я уверен что если бы я выкатил свой фреймворк в паблик то сразу бы получил парочку пулреквестов по безопасности. Вот 100% уверен!
VolCh
29.03.2018 15:04Никто не говорит, что в процедурном стиле с глобальными переменными нельзя сделать. Я много лет так сам делал во времена массового распространения PHP3. Но даже тогда как-то более поддерживаемыми получались приложения, которые по сути эмулировали ООП подход. Грубо, вместо объектов были ассоциативные массивы, которые функции с именами типа ClassName_MethodName получали в качестве первого параметра $this :)
michael_vostrikov
30.03.2018 05:46Личные сайты в профиле — в этом стиле и сделаны (там и БД, и юзеры/профили, форм навалом, файлы и превьюшки, защита от XSS...)
А можете пару ссылок скинуть?)
Mendel
30.03.2018 11:55)))) Тонко.
Уточню для Антона — нет, ссылки в вашем профиле не видны окружающим.
Ztare
28.03.2018 18:50+1Это так странно, что любое приложение с внятной архитектурой в этом обсуждении называют(или подразумевают) фреймворком. Это проблема понимания и терминологии, я бы фреймворком только каркас для множества приложений называл, а не архитектуру одного проекта с реализацией базовых кусков.
Mendel
28.03.2018 19:37Ну а как же их разделить то множественный или единичный, если архитектура внятная?
Чисто по статистике?)
Ну вот я делаю сейчас одностраничник. Интерфейс для смартконтракта эфировского.
На ангуляре. Ну плюс немного преферанса и поэтесс, но по сути одностраничник.
Фреймворк тащить — смысла нет.
Взял старый проект. MVP лендинга. Ну не делаю я одностраничники.
По сути минимальный набор для одностраничника на котором был сделан ровно один сайт, но все универсальное лежало в отдельной папке, так что пиши не хочу.
Каркас? Каркас. Для множества? Спорно. Можно было, но не использовалось.
Сейчас быстренько освежил, чтобы глаза не мазолило (писалось два года назад).
С заделом на то, чтобы можно было потом опять использовать.
Но скорее всего та же участь постигнет, и умрет оно, только в виде учебных примеров разве что будет использоваться…
В общем не нравится мне такая классификация)Ztare
28.03.2018 22:28Ну не знаю, я бы оценивал если больше одного приложения с одинаковым ядром без изменений, то можно и назвать фреймворк. Не теоретическая применимость в качестве основы для нового продукта, а именно использование в нескольких с неизменной структурой. Просто если смотреть на саму возможность переиспользования базы кода, то почти любой проект с чёткой структурой можно фреймворком называть.
Mendel
29.03.2018 12:17Что нужно сделать чтобы Луна стала планетой? Ну или крупные спутники гигантов, не суть. Планетой они станут когда изменят свою орбиту.
Т.е. с небесным телом ничего не поменяется, только контекст изменится. И тогда они станут другими объектами.
Считаю такую классификацию чистым легаси, и надеюсь ее таки пересмотрят (предпосылки есть). Ну и Плутон нам вернут, чего уж там (доминирует, не домнирует… нечеткое определение, зависимость от окружения..).
Не люблю определения которые зависят от контекста.
Ну или давайте возьмем другой мой проект, он не такой пограничный, там явно фреймворк. MVC, ORM (ActiveRecord), отдельно логика вьвов от шаблонов, СервисЛокатор, RBAC, авторизация, куча типовых модулей (почта, АктивФорм, кодогенерация… ну почти) и т.п.
На первых версиях было несколько десятков сайтов. По кодовой базе они были существенно разными, но по функционалу умеренно отличались.
Плюс еще биллинг одной компании я на нем делал.
Так что по вашему критерию явно выходит фреймворк.
Потом я очень существенно переделал АПИ, плюс название поменял,
дописал ему еще большую пачку модулей чисто CMS-ных, значительно переработал типовые шаблоны под большую модульность и гибкость.
В общем по факту вышел новый фреймворк «на базе» старого.
Ну и на нем было сделано полсотни сайтов.
Разных. Визитки, статейники, магазины, лендинги.
Но по коду они были все идентичны (я просто от тех кому нужны были сильные изменения в дизайне которые я не мог выжать в админке отказывался, ибо по цене часа работы я с вордпресоидами конкурировать не стану).
Все чисто данные (да, это были конфиги, но все редактировалось из админки, и хранилось в json а не в базе чисто ради скорости).
Так что реально можно сказать что это был один проект, просто много копий.
Так что по вашему критерию фреймворком он не являлся. И только когда я на нем написал очередной биллинг — спустя полсотни сайтов и полгода времени, он вдруг стал фреймворком. Вот только мне не совсем понятно — он стал фреймворком в день когда я начал писать биллинг? Или когда выкатил клиенту MVP? Или бету? Или в день релиза? В какой день он превратился в фреймворк?
Я бы сказал, что в любом нормально структурированном проекте есть фреймворк, а есть прикладная часть. Более менее четко можно говорить о том что «тут есть фреймворк» когда архитектор провел границу где ядро а где прикладное. Но по хорошему если архитектура кошерная, то это напрашивается само собой. Как минимум потому что модули разной степени «коровости» имеют разный уровень чувствительности к изменению внутреннего АПИ и совместимости, при развитии проекта.
VolCh
28.03.2018 21:37Фреймворк скорее технически диктует архитектуру, делает очень дорогими попытки выйти из её рамок. Преобладание принципа convention over configuration, куча действий, которые делаются автоматически, типа прошлись по папочке определённой и получили набор роутов из классов с суффиксом Controller и методов с суффиксом Action.
Ztare
28.03.2018 22:40+1Вот и получается что если фреймворком называть структуру взаимодействия модулей и обслуживающие функции, то каждое приложение, где они явно выделены можно называть «фреймворк» + «бизнес логика». А именно это похоже и предполагается теми, кто пишет что автор написал свой фреймворк. Но решение автора его самого в архитектуре не ограничивает, а даёт свободу выбора. В этом вроде и есть главный интерес
velvetcat
28.03.2018 12:59Огромное количество проблем в работе, совместимости и эксплуатации уязвимостей на моей памяти были связаны со словом «автоматически». А если не подгрузит «автоматически»? С инклудом хоть сразу видно будет.
Вы гораздо больше наделаете ошибок, если будете загружать файлы руками.
А если не подгрузит «автоматически»? С инклудом хоть сразу видно будет.
Просто надо знать, как работает твой инструмент. И тоже все будет сразу видно.
Fantyk
28.03.2018 10:42Тоже сразу вспомнил про Slim и Zend Expressive. Они содержат минимальный функционал, который в вашем приложении все равно придется реализовывать (роутинг и pipe).
Статья хорошая, но посыл отказаться от фреймворков для коммерческой разработки странен. Дома можно/нужно велосипедить как хочется, а в команде нужны договоренности и стандарты.
Тут кстати больше повезло приложениям, которые перешли на PSR пакеты из состояния легаси PHP-приложение с «include-oriented архитектурой». Вот они действительно не зависят от фреймворка.
Akuma
28.03.2018 11:20Сама статья довольно странная, но посыл я поддерживаю в какой-то степени.
Раньше использовал Symfony и радовался как ребенок, но когда потребовалось реализовать действительно нестандартный проект — это оказалось ужасом. Сейчас Symfony мне кажется медленным монстром, 90% кода которого непонятно для чего использовать. Конфиги-ради-конфигов.
Последнее время перешел на Silex: используется тот же самый функционал, но он гораздо меньше и соответственно проще и быстрее. Фреймворк используется только для самых базовых вещей, а все остальное реализуется библиотеками + своим кодом.nitso
28.03.2018 14:16Вы немного опоздали с переходом на Silex: https://symfony.com/blog/the-end-of-silex
Для использования базовых вещей фреймворка на сегодняшний день можно успешно пользоваться Symfony MicroKernel и не тянуть за собой ненужные зависимости. При этом, у вас будет возможность легко и быстро подключить необходимый функционал буквально парой строк. И он будет соответствовать общепринятым стандартам/практикам, понятен всем и лёгок в дальнейшей поддержке. Symfony Flex подталкивает к этому подходу.Akuma
28.03.2018 14:52+1Эм, ладно с «последнее время» погорячился. Года 3-4 уже. Так что не опоздал )
evgwed
28.03.2018 12:39Полезная статья для понимания общих и базовых принципов во фреймворках, спасибо. Зачастую не всегда в документации к фреймворку объясняется почему именно так сделано, а просто говорится «делай так и так». Большинство начинающих программистов не понимая этих подходов, принципов и их назначение, начинают писать на фреймворке так, что лучше бы не писал вообще код.
Раньше у symfony было что-то подобное в документации, объясняли все по полкам что и зачем. Как это сделать самому и как это сделано в symfony.
А вот в документации по yii вообще все грустно… Не рекомендовал бы для новичков, хотя и простой инструмент.
dmtrrr
28.03.2018 12:54+2Когда в следующий раз начнёте новый проект, постарайтесь обойтись без PHP-фреймворка
Это полумеры, когда в следующий раз начнёте новый проект, постарайтесь обойтись без PHP.
KirEv
28.03.2018 13:38+1ожидание: узнать интересное про РНР без фреймворков
реальность: неймспейсы, компосер, сторонние компоненты других разработчиков
I am confused.
но на минуточку
О возможности стать лучше как разработчик
Возможно, главным плюсом отказа от фреймворка станет знание, как всё работает под капотом. Вы будете видеть, что происходит, не полагаясь на фреймворк, который заботится о вас настолько, что вы не можете что-то отладить или до конца понять.
интересный разбор «как все под капотом», заюзав готовые компоненты без анализа.
статьи из категории «Выпендрежь» и «Не как все».VolCh
28.03.2018 21:45Ну, многие современные фреймворки не сильно отличаются по идеологии от конечного результата в посте. Собственно код фреймворка минимален, он лишь клей для самодостаточных компонентов и пользовательского кода. Да, по чистой случайности может оказаться, что 90% компонентов от того же вендора, что и фреймворк, но это не меняет факта, что собственно современный фреймворк это клей, а не монолит с хуками.
gavrilovm
28.03.2018 16:10Если есть уйма времени и желание прокачать скилы тогда разработка без фрейворка будет не только полезной, но и интересной. И также можно обойтись без использования уже говтовых компонентов, а остановится исключительно на самописе. Да, это будет интересно потому что можно разработать свой обработчик зависимостей, свой midleware, свой ORM и все другие важные коспоненты современного приложения. Прокачать скилы по части архитектуры ПО. Да и вообще увлекательно покодить.
У меня такого количества времени нет. Да и скилы норма.
sayber
28.03.2018 16:16Очередной трехколесный на чужих компонентах.
В итоге получаем тот же продукт, который не хотим использовать.
А иногда даже крупнее популярных продуктов и вероятно менее надежно/оптимизированно.
olegl84
28.03.2018 16:26Если делаю консольное приложение, всегда применяю такой подход на продакшене.
FSA
28.03.2018 16:40Можно было бы пройти через тягомотину написания собственного автозагрузчика
А чего там писать? Если надо быстро грузить нужные классы, достаточно использовать три строчки.
set_include_path(get_include_path(). PATH_SEPARATOR.__DIR__.'/classes/'); # или даже set_include_path(__DIR__.'/classes/'); spl_autoload_extensions('.php'); spl_autoload_register();
Тут, конечно, PSR-а никакого нет, зато минимум кода, работает автозагрузка из коробки, включая пространства имён, работает чрезвычайно быстро и не загружая лишний раз железо сервера. Маленькое неудобство есть — имена файлов должны быть названы в нижнем регистре (сами классы и пространства имён могут быть названы как угодно). Расширение файла или даже суффикс можно прописать во второй строке, например, '.class.php'.
Кстати, странно, что в PHP до сих пор не сделали штатную автозагрузку по всем правилам PSR.
Botchal
28.03.2018 17:16Когда в следующий раз начнёте новый проект, постарайтесь обойтись без PHP-фреймворка
А потом задумайтесь сколько слёз прольёте и Вы, и ваши коллеги и может быть те, кому этот проект потом достанется. И как вы обоснуете своё решение об отказе от стандартизации разработки (в данном контексте использование популярного фреймворка) в пользу велосипеда? Ну вот представьте, пролетают 2 года, проект выстрелил, нанимаем на работу ещё 2 программистов. Это обычные парни (или девушки). Они тебя спросят, а почему собственно тут велосипед. Вы им реально скажите что-то типа «Ну я хотел прокачать скилл, поэтому». Я думаю никому тут не нужно объяснять, что разработка на фреймворке это априори быстрее чем разработка велосипеда и разработка на велосипеде. Своим решением начать новый проект не на фреймворке вы подставляете и себя и коллег. И ещё интересная мысль, а почему собственно работодатель должен оплачивать Ваши дополнительные часы разработки за свой счёт. Или Вы уже все сами решили и за коллег и за работодателя? По факту это деньги за дыру и за Ваш скил. В общем на мой скромный взгляд вся эта идея — проявление эгоизма. И очень надеюсь, что всесуществалюди, которые так делают будут встречать в своей жизни одни новые проекты на разных велосипедах, не документированный код, отсутствие тестов и т.п. проявления эгоизма. А чё, зато прокачаете скил…VolCh
28.03.2018 21:57Данный подход как раз о стандартизации разработки. Приложение или фреймворк, которые оперируют PSR будут понятны любому. Например, не важно в большинстве случаев, как дошёл до контроллера Request или как зарегистрирован в контейнере какой-то сервис, если контракт запроса и контейнера ночью разбуди и расскажешь.
marsdenden
28.03.2018 17:30Наваяем фреймворк, чтобы избавиться от фреймворков… напомнило «надо, чтобы все хорошие поубивали всех плохих»
Yago
28.03.2018 17:56+1А мне нравится такой подход. Взять готовые популярные библиотеки и адаптировать под свой каркас с необходимыми интеграциями. Сделать свое ядро на основе хорошо работающих и протестированных решений от других разработчиков, предоставив интерфейсы модулям для инициализации приложения.
Делали так на одном проекте (rest api). Очень понравился результат. Код стал намного чище и гибче.
werevolff
29.03.2018 03:00Судя по плюсам к данной статье, похапешники продолжают оставаться программистами низшего сорта. Ты можешь вытащить похапешника из говнокода, но говнокод из похапэшника не выведешь никогда.
dzsysop
29.03.2018 03:52Ну вот не надо тут холиваров :-) говнокод в РНР — да, так сказать норма. Но если мы будем все же смотреть на те же фреймворки, они сделаны людьми с прямыми руками и для людей с прямыми руками. Просто РНР код всегда легко прочесть, он под рукой. Я уверен (по опыту) в других языках (той же Жаве) тоже полно говнокода в проектах, просто там все так построено, что код «соседа» редко читаешь, ну и таки да, порог входа для новичков значительно выше. Но профи они и на РНР профи, и обсуждение этой статьи это хорошо иллюстрирует.
Mendel
29.03.2018 12:28В пхп качество кода написанного новичками — заметно хуже.
Плюс количество новичков существенно выше ибо порог вхождения ниже.
Но если отбросить пласт «динозавров» которые плачут что в пхп7 убрали совместимость с синтаксисом пхп4, и им подобных, если убрать тех кто говорит «я чуть чуть знаю пхп… ну как знаю — могу правильно расставить пхп-теги в шаблоне вордпресса», то картина будет абсолютно одинаковая.
Ну ок, давайте для строгости введем определение — первые будут пхп4-программистами, даже если они и используют функционал пхп5, но идеологически застряли в старом апи, вторые будут пхп-верстальщики, а уже «полноценые» это будут пхп7-программисты.
Вот у пхп7-разработчиков (особенно если с включенным стрикт-режимом и покрытием тестами) все ок.
demimurych
обьясните мне пожалуйста почему первая цитата не исключает действия из второй? почему в первом случае нас агитируют заниматься тягомотиной, а во втором случае нет?
serginho
Потому что фреймворк это не загрузчик, наверное :)
Mendel
Вот да.
С одной стороны как человек который таки да, писал все с нуля, и действительно серьезно подтянул скилсы в чужих фрейворках — да, это как-то странновато использовать готовые пакеты пытаясь написать «с нуля». Тем более что внутрянку пакетов не затронули. С другой стороны… ну вот минимальный базовый функционал, так чтобы оно реально было применимо в продакшене — меньше 20килобайт кода не завесит. Плюс PSRы разобрать, объяснить. Тесты и т.п… В общем статей сорок уйдет на примерно тоже самое.
А так хоть стандарты людям будут известны.
Итого: Да, статья не очень соответствует заголовку и началу, но полезно. Местами.
ozonar
Я честно говоря не понимаю, чем по сложности такой способ «без фреймворка» отличается от, собственно, разбора фреймворка.
Работать на таком монстре будет сильно сложнее, понимания работы конкретных элементов он не добавил; в итоге получился просто фреймворк из компонентов других фреймворков (правда без нормальной работы с базой), полезность которого сомнительна
Mendel
Без базы, без шаблонизатора, без MVC… много еще без чего.
Вообще вы конечно правы, это я что-то затупил под вечер.
У меня мой фреймворк занимает чуть больше мегабайта кода.
Неоднократно порывался выложить в паблик, кратенько писать «историю создания» примерно в таком стиле и т.п.
И тут на автопилоте ощущения от того масштаба работы взял, да и сравнил с вот этим вот куцым описанием процесса сборки из кусочков.
Действительно, если так по верхам описывать как здесь, то будет ничуть не больше. Правда и ничуть не понятнее).
evgwed
Идея интересная, но так как у подобных решений нет нормальной документации, будет крайне неудобно поддерживать проект на этом велосипеде (и пусть он использует много фишек типа PSR, DI и прочего).
Вопрос работы с бд тоже довольно холиварная тема, поэтому ее и не описывал автор. Сложно будет доказать когда оправдан ActiveRecord, а когда DataMapper. И там тоже все на магии, если самому реализовывать.
Данная статья удобна для стажеров. Буду давать ее для изучение перед изучение полноценных фреймворков.