View
1.908
Download
5
Embed Size (px)
DESCRIPTION
Общее введение в пространства именв PHP.
Citation preview
Модульная структураPHP-приложений
Interlabs
25 февраля 2013
1 / 27
В чем проблема
PHP < 5.3: NIH-синдром
Каждый фреймворк — вещь в себе, малая доля использованиястороннего кода.
Необходимо стандартное решение:
• отсутствие конфликтов имен;• удобная установка и загрузка;• автоматическое управление зависимостями.
2 / 27
История вопроса, до 5.3
Практически полное отсутствие стандартов
• каждая библиотека использует собственную структуруимен;
• единственный стандарт — PEAR, там все плохо.• нет поддержки пространств имен на уровне языка;
Каждый выкручивается как может.
3 / 27
Пространства имен до 5.3
• сделать вид что проблемы нет — неизбежные конфликты.• или использовать префиксы в именах классов:
Zend_Db_TableZend_Controller_RequestZend_Controller_Plugin_PluginInterface
Zend — vendor, DB, Controller, Plugin — вложенные модули.
Конфликты минимизированы, но неудобно.
4 / 27
Структура файлов до 5.3
Стандарты отсутствуют.
Два основных варианта:
• стиль Java: каждый класс в отдельном файле, процедурныйкод — как придется
• стиль Perl/Python/Ruby: файл — модуль, состоящий изнабора классов и процедурного кода.
Как правило собственный загрузчик кода, явная подгрузкамодулей.
5 / 27
История вопроса, после 5.3
• поддержка пространств имен на уровне языка;• начало процесса стандартизации;• PEAR не нужен;• появление нормально реализованных средств управлениямодулями;
• постепенный переход ключевых библиотек и приложенийна новую систему.
6 / 27
Пространства имен в PHP
namespace Interlabs\DBI;
use Interlabs\Common\Exception;use Interlabs\Common\Object as BaseObject;
class Connection extends BaseObject;{
...
throw new Exception\BadPropertyException(’...’);}
namespace устанавливает текущее, use — импортирует илиопределяет псевдоним.
7 / 27
Пространства имен: особенности
• namespace — первое PHP-выражение в файле;• один файл может содержать несколько пространств имен(но так не принято);
• класс относится к пространству имен, в котором онопределен;
• при определении класса указывать пространство в именинельзя;
• функции тоже можно включать в пространства имен, но вмеру бесполезно (см. нижe);
8 / 27
Разрешение имен
Foo Unqualified Name просто имяFoo\Bar Qualified Name относительное имя\Foo\Bar Fully Qualified Name абсолютное имя
1 абсолютные имена сразу разрешаются2 внутри namespace пытаемся разрешить относительноимпортированных пространств имен (use)
3 если не получилось — разрешаем относительно текущегопространства
4 простые имена функций разрешаются относительноготекущего пространства, если не получается —относительно глобального.
9 / 27
СтандартизацияДля того, чтобы пространства имен реально работали, нужнастандартизация.
Framework Interop Group http://php-fig.org
На данный момент — целых 4 стандарта1
• PSR-0 — автозагрузка и модульная структура;• PSR-1 — стандарт именования;• PSR-2 — стиль кодирования;• PSR-3 — стандартный интерфейс логирования.
1Для сравнения — в Python сотни стандартов, используемых иразвиваемых
10 / 27
PSR–0• каждый класс — в отдельном файле c именем класса;• подгрузка — автоматически;
• стандартная структура пространства имен:\<Vendor Name\(<Namespace>\)*<Class Name>
• структура файлов соответствует имени, \ — подкаталоги:\Interlabs\DBI\Platform\MySQLsrc/Interlabs/DBI/Platform/MySQL.php
• режим совместимости со старым кодом:Framework_Module_Somethingsrc/Framework/Module/Something.php
• эталонный код загрузчика классов.
https://github.com/php-fig/fig-standards/blob/master/accepted/PSR–0.md 11 / 27
PSR–0: выводы и слабые места
1 лучше безобразно, но единообразно;2 отсутствует концепция модуля как таковая, базоваяединица — класс;
3 функции внутри пространств имени малополезны, так какавтозагрузка только для классов;
4 отсутствует стандартный API для обработки событий,например, события загрузки класса.
5 отсутствует стандарт на Vendor prefix.
Стандарт принят, нужно ему следовать.
12 / 27
Autoloader• автоматическая подгрузка классов и интерфейсов;• реализовано в версии 5, в 5.3 доведено до ума;• реализуется путем определения специальной глобальнойфункции __autoload();
• если файловая структура и имена стандартизированы —можно использовать.
function autoload($className){
$className = ltrim($className, ’\\’);$fileName = ’’;$namespace = ’’;if ($lastNsPos = strrpos($className, ’\\’)) {
$namespace = substr($className, 0, $lastNsPos);$className = substr($className, $lastNsPos + 1);$fileName = str_replace(’\\’, DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
}$fileName .= str_replace(’_’, DIRECTORY_SEPARATOR, $className) . ’.php’;
require $fileName;}
13 / 27
Рекомендуемая структураприложения
• основная единица кода — класс;• каждый класс определен в некотором пространстве имен;• каждый класс в отдельном файле, путь к файлусоответствует пространству имен;
• пространства имен образуют иерархию;• корень иерархии — vendor prefix;• все подгружается автоматически, явные include и requireдля загрузки кода не используются;
• если нужен процедурный интерфейс — класс состатическими методами;
• константы — тоже в классах.
14 / 27
Кеширование кода классов
• большое количество небольших файлов с кодом классов• большое количество обращений к файловой системе закодом класса;
• существенные накладные расходы на интерпретацию.
Кеширование кода обязательно!
APC, eAccelerator, Zend Accelerator, . . .
15 / 27
Использование внешнего кода иуправление зависимостями
Нужно управлять сторонним кодом, PEAR не предлагать.
Composer
http://getcomposer.org/
• простая установка внешних библиотек;• отслеживание версий;• отслеживание зависимостей;• простое обновление до свежих версий;• встроенный autoloader.
16 / 27
composer: установка$ curl -sS https://getcomposer.org/installer | php$ vim /path/to/project/composer.json--------------- composer.json --------------------{
"require": {"php": ">=5.3.0","monolog/monolog": "1.0.*"
},"autoload": {
"psr-0": {"Interlabs": "src/"
}}
}--------------------------------------------------$ php composer.phar install
17 / 27
composer: результат
src/ — создаем каталог для нашего кода;vendor/ — стандартный каталог для внешних библиотек;
autoload.php — код первоначальной загрузки.composer/ — код загрузчика классов... — файлы внешних библиотек
В файле запуска приложения остается сказать:
require ’vendor/autoload.php’;
18 / 27
Добавление и обновлениеДобавление: прописываем в composer.json и вызываем
$ php composer.phar install
Для обновления библиотек до последних версий вызываем
$ php composer phar update
Версии пакетов: точная версия 1.0.2, диапазон >=1.0,<2.0,маска 1.0.*, значимый релиз ∼1.2.
Используемые версии фиксируются в файле composer.lock.19 / 27
Откуда берутся пакеты
Пакеты берутся из репозиториев, центральный репозиторий:
Packagist
http://packagist.org
• собственные репозитории (Satis);• репозитории систем контроля версий (git, hg, SVN);• PEAR.
20 / 27
Установка из git-репозитория
Для установки пакета можно использовать любойgit-репозиторий:
"repositories": [{
"type": "git","url": "http://git.example.com/my/project","reference": "master"
}]
21 / 27
Legacy-кодДля старых библиотек описание пакета можно включатьнепосредственно в composer.json проекта:
"repositories": [{
"type": "package","package": {
"name": "my/project","source": {
"type": "git","url": "[email protected]:repo.git"
}]
}
22 / 27
Метаданные проектаcomposer.json — описывает не только зависимости, но и сампроект.
{ "name": "company/component","description": "some component","type": "library","homepage": "http://www.example.com","version": "0.7.1","authors": [
...]
}
Знакомство с проектом начинаем с composer.json.
23 / 27
Пример: silex{ "name": "silex/silex",
"description": "The PHP micro-framework based on the Symfony2 Components","keywords": ["microframework"],"homepage": "http://silex.sensiolabs.org","license": "MIT","authors": [
{ "name": "Fabien Potencier", "email": "[email protected]" },{ "name": "Igor Wiedler", "email": "[email protected]" }
],"require": {
"php": ">=5.3.3","pimple/pimple": "1.*","symfony/event-dispatcher": ">=2.1,<2.3-dev","symfony/http-foundation": ">=2.1,<2.3-dev","symfony/http-kernel": ">=2.1,<2.3-dev","symfony/routing": ">=2.1,<2.3-dev" },
"require-dev": {"symfony/security": ">=2.1,<2.3-dev",
"symfony/config": ">=2.1,<2.3-dev","symfony/validator": ">=2.1,<2.3-dev","twig/twig": ">=1.8.0,<2.0-dev","doctrine/dbal": ">=2.2.0,<2.4.0-dev","swiftmailer/swiftmailer": "4.2.*" },
"suggest": {"symfony/browser-kit": ">=2.1,<2.3-dev","symfony/css-selector": ">=2.1,<2.3-dev","symfony/dom-crawler": ">=2.1,<2.3-dev" },
"autoload": {"psr-0": { "Silex": "src/" }
},}
24 / 27
Обработка событий
В процессе установки (обновления) пакета можно запускатьобработчики событий:
pre-install-cmd post-install-cmd pre-update-cmdpost-update-cmd pre-package-install post-package-installpre-package-update post-package-update pre-package-uninstallpost-package-uninstall post-autoload-dump
• вызовы методов классов, Composer\Script\Event вкачестве параметра;
• запуск внешних программ;
25 / 27
Описание обработчиков{ "scripts": {
"post-install-cmd": ["Vendor\Class::updateCache","phpunit -c app/"
]}
use Composer\Script\Event;class Handler{
public static function updateCache(Event $event) {{//...}
}
26 / 27
Что читать
• http://php.net/manual/ru/language.namespaces.php —пространства имен;
• http://php.net/manual/ru/language.oop5.autoload.php - автозагрузка;
• http://getcomposer.org/doc/ — работа с Composer;• http://packagist.org — центральный репозиторийпакетов Composer;
• http://getcomposer.org/doc/articles/handling-private-packages-with-satis.md —организация собственных репозиториев.
27 / 27