Powered by CodeIgniter

Уроки

(28)
14
16 голосов
Учиться, учиться и еще раз учиться — развитие личности идет таким путем.
Открываю цикл рассказов о второй версии cogear следующим материалом.

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

Весь жизненный цикл одной итерации cogear² расположен в главном файле — index.php.

Установка постоянных

<?php /** * Cogear — simple and fast site management system. * * Created by Dmitriy Belyaev at the year of 2011. * * "Life is like the development. But the last one never ends." — Dmitriy Belyaev */ // Version define('COGEAR', '2.0'); // Constants define('DS', DIRECTORY_SEPARATOR); define('PS', PATH_SEPARATOR); define('EXT', '.php'); define('ROOT', realpath(dirname(__FILE__))); define('GEARS_FOLDER', 'gears'); // Core gears define('ENGINE', ROOT . DS . 'engine'); // Gears for all sites define('GEARS', ROOT . DS . 'gears'); define('SITES', ROOT . DS . 'sites'); define('DEFAULT_SITE', SITES . DS . 'default'); define('PHP_FILE_PREFIX', '<?php ' . "\n"); define('IGNITE', time()); // Define error reporting level error_reporting(E_ALL | E_STRICT); Для начала следует определить все пути и задать важные константы.

Автозагрузка

Еще пользуетесь прожорливыми функциями include и require? Тогда мы идем к вам.
В cogear² все классы загружаются автоматически при использовании правил и наименования пространства имен.
/** * Autoload * * @param $class Class name. * @return boolean */ function autoload($class) { $filename = str_replace('_', DS, $class); if ($path = find($filename.EXT)) { include $path; return TRUE; } return FALSE; } // Register with autoload spl_autoload_register('autoload'); Помним, что include внутри автозагрузчика оптимизирован в ядре PHP > 5.2, и потребляет много меньше ресурсов.

Слоеный пирог

Задумка данной концепции состоит в том, чтобы разделить ядро системы (/engine), шестеренки для всех сайтов (/gears) и шестеренки для текущего сайта (/sites/адрес_сайта/gears).
Когда автозагрузчик ищет класс, то он обходит папки в обратной последовательности. Таким образом вы можете переназначить шестеренку ядра только для определенного сайта или же ставить и обновлять шестеренки для всех сайтов сразу.
/** * Search for file — layerd pancake ideology * * @param string $file * @return string|array */ function find($file) { $paths = array( ENGINE . DS . $file, ENGINE . DS . 'Core' . DS . $file, GEARS . DS . $file, ); defined('SITE') && $paths[] = SITE . DS . GEARS_FOLDER . DS . $file; $result = array(); while ($path = array_pop($paths)) { if (strpos($path, '*') !== FALSE && $files = glob($path)) { foreach ($files as $file) { $result[str_replace($path, '', $file)] = $file; } } elseif (file_exists($path)) { return $path; } } return $result ? $result : FALSE; }

Скромный дебаг

Грешно, каюсь, но простяцкий дебаг полезен везде.
/** * Simple debug * * @param mixed $data */ function debug() { echo '<pre>'; $args = func_get_args(); call_user_func_array('var_dump', $args); echo '</pre>'; }

Поехали!

Гагарин с нами. Запускаем cogear².
$cogear = Cogear::getInstance(); $cogear->request = new Request(); // Set host $host = $cogear->request->get('HTTP_HOST'); // Defince site folder // Check if main if (substr_count($host, '.') > 1) { if (!is_dir(SITES . DS . $host)) { list($subdomain, $host) = preg_split('#[\.]+#', $host, 2, PREG_SPLIT_NO_EMPTY); define('SUBDOMAIN', $subdomain); } } defined('SITE') OR is_dir(SITES . DS . $host) && define('SITE', SITES . DS . $host) OR define('SITE', DEFAULT_SITE); define('SITE_GEARS', SITE . DS . GEARS_FOLDER); Инициализируем базовый класс запроса.
Определяем:
  • хост,
  • поддомен, если он есть,
  • текущий сайт,
  • папку с шестеренками сайта.

$cogear->config = new Config(SITE . DS . 'settings' . EXT); define('DEVELOPMENT', $cogear->config->development);
Тут же читаем конфиг сайт (класс загружается сам). Здесь стоит обратить внимание, что классы ядра расположены в папке /engine/Core, но могут в своем название префикс Core_ не носить. Это сделано специально для сокращения печатаемого кода.

Помним, что конфиги хранятся в виде обычного массива, а читать мы их можем следующим образом:
config('user.profile.avatar.size','64x64'); // последним можно значение по-умолчанию приткнуть //Внутри шестеренки $this->get('user.profile.avatar.size','64x64'); //Там где у нас нет прямого доступа к ядру, а функцию config мы не используем по религиозным убеждениям $cogear = getInstance(); $cogear->get('user.profile.avatar.size','64x64'); //Или cogear()->get('user.profile.avatar.size','64x64'); Писать в конфиги можно как строки, так и массивы и делается это одним способом:
//Внутри шестеренки $this->set('user.profile.avatar.size','200x200'); //Вне шестеренки cogear()->set('user.profile.avatar.size','200x200'); Обратите внимание, что точки — это показатели вложенности массива. В итоге подобной манипуляции с конфигом внтури его файла вы увидите такой код:
… 'user' => array ( 'profile' => array ( 'avatar' => array ( 'size' => '32x32', ), ), ), …
Едем дальше. Еще немного констант.
$folder = basename(ROOT); if (!in_array($folder, array($host,'www', 'public_html', 'htdocs', SITE))) { define('SUBDIR', $folder); $host .= '/' . SUBDIR; } if (($port = $cogear->request->get('SERVER_PORT')) != 80) { $host .= ':' . $port; } define('SITE_URL', $host); // Define uploads folder defined('UPLOADS') OR define('UPLOADS', SITE . DS . 'uploads'); Наконец-то корректно определение поддиректории и порта сайта. Можно вешать сайты на IP-шники и класть в подпапки.

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

Далее грузим кеш (системный и обычный), запускаем роутер, харвестр файлов JS и СSS, класс ответа и сессии. Одним словом то, без чего нельзя обойтись.
$cogear->system_cache = new Cache(array('adapter' => 'Cache_Adapter_File', 'path' => SITE . DS . 'cache' . DS . 'system', 'enabled' => !DEVELOPMENT)); $cogear->cache = $cogear->config->cache ? new Cache($cogear->config->cache) : $cogear->system_cache; if (!$options = $cogear->config->cookies) { $options = array( 'name' => 'session', 'cookie_domain' => '.' . SITE_URL, ); } $cogear->router = new Router(); $cogear->assets = new Assets(); $cogear->response = new Response(); $cogear->session = Session::factory('session', $options); Системный кеш отличается от обычного тем, что его можно не стирать, т.к. он используется как постоянное хранилище системных данных.

Грузим конфиг настроек.
// Load current site settings if file exists $cogear->config->load(SITE.DS.'config'.EXT); Да, да, у вас не двоится в глазах. В settings.php хранятся базовые настройки, такие как соединение с БД. После установки движка на домен он заливается бетоном (права 0644), чтобы никто не мог напортачить, положив сайт.
Настройки же шестеренок дампятся в config.php, таким образом вы можете легко переносить настройки с сайта на сайт.

Финал. Грузим шестеренки. Цепляем события и сохраняет отработанный цикл ядра (сохранение переменых в файл, если таковые были добавлены за итерацию).
// Load gears $cogear->loadGears(); event('ignite'); event('done'); $cogear->save(); event('exit');

Вуаля. Стоит сказать, что на локальной машинe в комплекте Denwer PHP5.3 + eAccelerator движок потребляет сейчас около 150Кб за итерацию.
Количество включенных шестеренок оцените сами:


В следующий раз расскажу про систему хуков и событий.
22:15 ← 25 июля 2011 Отправить в Твиттер adminadmin  RSS comments 20

Комментарии (20) ↓

JiLiZART JiLiZART time 22:37 ← 25 июля 2011 #
Отлично :)
Isildien Isildien time 22:56 ← 25 июля 2011 #
Как всегда интересные статьи, ждем продолжения банкета :)
Graid Graid time 23:59 ← 25 июля 2011 #
Отлично! Жду не дождусь первых «несистемных»(блог, рейтинг,etc) шестеренок.
Одно только настораживает, хранить конфиг в массиве… Редактирование конфигов вручную для многих приобретет зловещий смысл.
Автор
admin admin time 00:01 ← 26 июля 2011 #
Разве я похож на идиота? :-) Массив — это на первых порах, для хардкодинга. Потом все настройки будут редактироваться через красивый UI.

По-сути, хранить в виде массива в одном файле — оптимальное решение. Потому как конфиг всегда грузится, каждый раз. Пихать его в базу и перекешировать — зачем? И потом намного проще разобраться в массиве при хардкодинге, чем править таблички через phpMyAdmin.
Graid Graid time 00:15 ← 26 июля 2011 #
Но ведь UI еще надо запустить, а для этого как раз бывает надо залезть в конфиг. Про БД я не говорю, это для обычного юзвера вообще жесть.
Автор
admin admin time 00:21 ← 26 июля 2011 #
Можно сейчас уже любые конфиги через формы ворочить.
Напишу об этом статью.
Graid Graid time 00:24 ← 26 июля 2011 #
То есть шестеренка формы автономна?
Автор
admin admin time 00:53 ← 26 июля 2011 #
Внутри движка — да.
Graid Graid time 08:41 ← 26 июля 2011 #
Но ведь движек может не подниматься. Например при переносе с хостинга на хостинг, ошибке в конфиге, etc. Тут то как раз UI ничем не поможет, правильно?
Автор
admin admin time 09:25 ← 26 июля 2011 #
Вопрос. Причем тут настройки сайта? :-)
Graid Graid time 13:28 ← 26 июля 2011 #
Настройки сайта != Конфиг?
Автор
admin admin time 14:38 ← 26 июля 2011 #
Да. Есть настройки — settings.php, то без чего сайт работать не будет. А есть конфиг — config.php, то есть опции шестеренок, хранящиеся в дампе.
Graid Graid time 00:24 ← 26 июля 2011 #
Особенно если массив будет сериализован…
Автор
admin admin time 00:52 ← 26 июля 2011 #
Зачем его сериализовать? :-)
Читабельно?
<?php return array ( 'theme' => array ( 'logo' => '/theme/logo/logo.png', 'favicon' => '/theme/icon/favicon.ico', ), 'wysiwyg' => array ( 'editor' => 'redactor', ), 'cron' => array ( 'last_run' => 1311627030, ), 'user' => array ( 'profile' => array ( 'avatar' => array ( 'size' => '32x32', ), ), ), 'image' => array ( 'presets' => array ( 'avatar' => array ( 'small' => array ( 'size' => '24x24', 'actions' => array ( 0 => 'sizecrop', ), ), 'profile' => array ( 'size' => '32x32', 'actions' => array ( 0 => 'sizecrop', ), ), ), ), ), );
Graid Graid time 08:28 ← 26 июля 2011 #
Обычно массивы для хранения серилизуют, так то конечно выглядит читабельнее =)
Но все же ini'шники по мне более юзерфрендли.
Автор
admin admin time 09:26 ← 26 июля 2011 #
У них 2 уровня вложенности + посчитай расход на парсинг 100 ini-шек.
Graid Graid time 08:30 ← 26 июля 2011 #
И еще один вопросик, что означает
$file OR $file = $this->file;
, раньше такого вроде не встречал.
Автор
admin admin time 09:28 ← 26 июля 2011 #
Это джедайское программирование.
Аналогично тому:
if(!$file){ $file = $this->file; }
Если первая часть до OR будет положительной (не 0, FALSE, NULL), то до второй интерпретатор не дойдет.
Если же первая часть нулевая, то исполняется вторая проверка.
Ramir Ramir time 08:33 ← 26 июля 2011 #
Папки Gears нет. Это потому, что все Шестеренки сейчас «системные»?
Автор
admin admin time 09:26 ← 26 июля 2011 #
Да. Таки и есть.