Протофабрика на php, или как не зависеть от фреймворка

в 9:03, , рубрики: autoload, php, Веб-разработка, ооп, фабрика, фреймворки php, метки: , , , ,

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

Как пользоваться

Лежит он здесь: github.com/ytko/yNew

Закидываем в корень директории с классами (хотя, можно и куда-то еще, например в корень проекта — см. настройки).

Чтобы воспользоваться классом, один раз заинклудить его все-таки придется. Но учитывая распространение фронт контроллеров это просто: добавляем в точку входа (index.php) include_once PATH_TO_YNEW.'ynew.php';.

Иногда бывает, что точек входа несколько (с чем недавно столкнулся в netcat) — тогда ищем какой-то общий файл (какой-нибудь settings.php).

Теперь в любом месте после вызова yNew::load('className'); будет подключен файл className/className.php, а $var = yNew::create('className'); в придачу создаст объект класса className. Кроме того, в php 5.3 используется «магия» (__callStatic()) и создавать объект можно так: $var = yNew::className();

// просто подключаем файл className/className.php (относительно ynew.php)
yNew::load('className');
// и создаем объект по-миссионерски
$var = new className();

// то же самое, но в одну строчку
$var = yNew::create('className');

// или еще короче в php 5.3
$var = yNew::className();

// если нужно передать аргументы в конструктор, смело передаем
$var = yNew::create('className', $argument1, $argument2);

// php 5.3
$var = yNew::className($argument1, $argument2);

Небольшой полезный нюанс

Если класс уже есть, никаких инклудов не будет, и yNew::create() просто создаст объект нужного класса. За счет этого можно пользоваться дочерними классами какой-либо библиотеки, достаточно подключить основной файл.

// подключаем файл className/className.php
yNew::load('className');

// создаем объект определенный в className/className.php
$var = yNew::classNameNode();

// хотя, можно и так
$var = new classNameNode();

// зачем тогда огород городить?
// вот для этого (в случае, если сеттеры возвращают $this):
$var = yNew::className( yNew::classNameNode()->setSomething('smth') )
	->addNode( yNew::classNameNode()->setSmth('smthOther') );

// так это выглядит с new:
$node1 = new classNameNode();
$node1->setSomething('smth');
$node2 = new classNameNode();
$node2->setSomething('smthOther');
$var = new className($node1);
$var->addNode($node2);

// и так, конечно, тоже можно:
class foo {
	public $bar = 'bar';
}
echo yNew::foo()->$bar;

Структура

Что касается файловой структуры, здесь все уподобляется популярным фреймворкам: класс foo_bar должен находится в foo/bar.php, а foo_bar_baz в foo/bar/baz.php. Единственное, и foo, и foo_foo будут искаться в foo/foo.php.

Настройки

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

// меняем расширение файлов
yNew::$extension = 'inc.php';
// меняем путь
yNew::$path = 'classes';

// или создаем потомка
class myNew extends yNew {
	public static
		$extension = 'php5',
		$path = 'php5classes';
}

// получим classes/foo/foo.inc.php
yNew::load('foo');

// получим php5classes/foo/foo.php5
myNew::load('foo');

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

Теперь сами свойства:

  • $path = '': путь до директории с классами относительно yNew.php
  • $basePath = __dir__: путь до yNew.php (подставляется автоматически, но можно переопределить)
  • $delimiter = '_': разделитель, использующийся в названии класса (при '_' foo_bar находится в foo/bar.php)
  • $extension = 'php': расширение файлов
  • $allowMagic = true: разрешить ли магическую генерацию методов (yNew::foo() вместо yNew::create('foo'))

Autoload

Да, и конечно autoload никто не отменял, и чтобы с ним не возиться (нужен php 5.3, иначе добавляем yNew::load() вручную и перехватываем exception):

include_once 'ynew.php';
yNew::autoload();
$var = new foo();

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

Автор: urvalla


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js