В сети много устаревшей информации, которая вводит новых пользователей PHP в заблуждение, распространяя плохие практики и небезопасный код. PHP: The Right Way - это легко читаемый, краткий справочник PHP по популярным стандартам кодирования, ссылки на авторитетные руководства по всему интернету и то, что участники считают лучшими практиками в настоящий момент. Не существует канонического способа использования PHP. Цель этого веб-сайта представить новым PHP разработчикам некоторые темы, которые они могли не знать, долгое время, и нацелить опытных профессионалов на свежие идеи в тех темах с которыми они работали на протяжении лет без какого либо пересмотра. Этот веб-сайт также не расскажет вам какими инструментами пользоваться, но предложит советы для множества вариантов, когда возможно объяснит разницу в подходах и вариантах использования.
Это живой документ и будет продолжать обновляться с более полезной информацией и примерами, как только они станут доступными.
PHP: The Right Way переведено на множество различных языков:
Самая последняя версия PHP: The Right Way также доступна в PDF, EPUB и MOBI форматах. Перейти на Leanpub
Помогите сделать этот веб-сайт лучшим ресурсом для новых PHP программистов! Поддержать на GitHub
Если вы начали работать с PHP, начните с текущего стабильного релиза PHP 8.3. PHP 8.x добавляет много новых особенностей чем более старые 7.x и 5.x версии. Движок был в значительной степени переписан, и PHP сегодня намного быстрее чем более старые версии. PHP 8 - это крупное обновление языка, содержащее много новых особенностей и оптимизаций.
Вам необходимо быстро попробовать обновиться до последней стабильной версии - PHP 7.4 уже End of Life. Обновление - это просто, тут не так много 8.1, 8.2, 8.3. Если вы не уверены в какой версии содержится функция или особенность, вы можете проверить PHP документацию на веб-сайте php.net.
С PHP 5.4 или новее, вы можете начать изучение PHP без установки и настройки полноценного Веб-сервера. Для того чтобы запустить сервер, выполните следующую команду терминала в корневой директории вашего веб-проекта:
macOS поставляется с предустановленным PHP но это обычно немного более ранняя версия чем последний стабильный релиз. Есть несколько способов установить последнюю версию PHP в macOS.
Homebrew - это пакетный менеджер для macOS который помогает вам легко установить PHP и различные расширения. Главный репозиторий Homebrew предоставляет “formulae” формулы для PHP 7.4, 8.0, 8.1, PHP 8.2 и PHP 8.3. Установите последнюю версию командой:
brew install php@8.3
Вы можете переключаться между Homebrew PHP версиями изменяя переменную PATH
. Как альтернативу, вы можете использовать
brew-php-switcher для переключения PHP версий автоматически.
Также вы можете переключаться вручную между PHP версиями, отсоединяя и присоединяя желаемую версию:
brew unlink php
brew link --overwrite php@8.2
brew unlink php
brew link --overwrite php@8.3
Проект MacPorts - это инициатива open-source сообщества направленная на разработку простой в использовании системы для компиляции, установки, и обновления ПО с отрытым исходным кодом, на основе командной строки, X11 или Aqua в операционной системе macOS.
MacPorts поддерживает предварительно скомпилированные бинарники, поэтому вам не нужно пересобирать каждую зависимость из исходных tarball файлов, это спасет вас если в вашей системе не установлен какой-либо пакет..
Здесь вы можете установить php54
, php55
, php56
, php70
, php71
, php72
, php73
, php74
, php80
, php81
, php82
или php83
используя команду port install
, например:
sudo port install php74
sudo port install php83
И вы можете запустить команду select
чтобы переключиться на активную версию PHP:
sudo port select --set php php83
phpbrew это инструмент для установки и управления несколькими версиями PHP. Это может быть реально полезным, когда два разных приложения/проекта требуют разных версий PHP, и вы не используете виртуальные машины.
Прим. переводчика: устарело, не рекомендуется к использованию.
Еще один популярный способ - это php-osx.liip.ch который обеспечивает методы установки в одну строку для версий с 5.3 по 7.3. Это не перезаписывает бинарники PHP установленные Apple, а устанавливает все в отдельные места (/usr/local/php5).
Еще один метод, который дает вам контроль над версией PHP, которую вы устанавливаете, это сделай сам. В этом случае, также обязательно установите Xcode или заменитель “Command Line Tools for XCode” скачиваемый из Apple’s Developer Center.
Перечисленные выше решения в основном обрабатывают сам PHP и не предоставляют такие вещи как Apache, Nginx или SQL-сервер. Решения “Все в одном” такие как MAMP или XAMPP установят для вас те другие части программного обеспечения и свяжут их все вместе, но простота настройки идет в ущерб гибкости.
Вы можете скачать бинарники из windows.php.net/download. После извлечения PHP, рекомендуется установить PATH на коневую папку PHP (где находится php.exe) для того чтобы вы могли выполнять PHP из любого места.
Для изучения и локальной разработки, вы можете использовать встроенный веб-сервер с PHP 5.4+ так что вам не нужно беспокоиться об этой настройке. Если вы хотите что-то наподобие “все в одном”, которое включало бы полноценный веб-сервер а также MySQL, тогда такие инструменты как XAMPP, EasyPHP, OpenServer и WAMP помогут быстро настроить и запустить среду разработки Windows. Тем не менее, эти инструменты будут немного отличаться от production, так что будьте осторожны с различиями в средах, если вы работаете в Windows, а развертывание производите в Linux.
Если вам нужно запустить свою production систему в Windows, тогда IIS7 даст вам самую лучшую стабильность и производительность. Вы можете использовать phpmanager (GUI плагин для IIS7) для того чтобы упростить настройку и управление PHP. IIS7 поставляется со встроенным FastCGI и готов к работе, вам просто нужно настроить PHP обработчик. Для поддержки и дополнительных ресурсов есть выделенная область на iis.net for PHP.
Как правило, запуск вашего приложения в разных средах разработки и production может привести к появлению странных ошибок запуска. Если вы разрабатываете в Windows а развертывание осуществляете Linux (или на чем-нибудь не-Windows) тогда вам следует рассмотреть возможность использования Virtual Machine.
У Chris Tankersley есть очень полезный пост в блоге о том, какие инструменты он использует для PHP разработки в Windows.
Большинство GNU/Linux дистрибутивов идут в составе с PHP доступным из официальных репозиториев, но эти пакеты обычно немного отстают от текущей стабильной версии. Есть несколько способов получить последние версии PHP в этих дистрибутивах. Например в Ubuntu или базирующихся на Debian GNU/Linux дистрибутивах, лучшей альтернативой родным пакетам являются предоставляемые и поддерживаемые Ondřej Surý, через его персональный архив пакетов (PPA) в Ubuntu и DPA/bikeshed в Debian. Инструкции для каждого из них вы найдете ниже. При этом вы всегда можете использовать контейнеры, скомпилировать исходный код PHP и т. д.
Для Ubuntu дистрибутивов, PPA by Ondřej Surý предоставляет поддерживаемые версии PHP вместе со многими расширениями PECL. Для добавления этого PPA в вашу систему, проделайте в терминале следующие шаги:
Сначала добавьте PPA в источники программного обеспечения вашей системы с помощью команды:
sudo add-apt-repository ppa:ondrej/php
После добавления PPA обновите список пакетов вашей системы.:
sudo apt update
Это гарантирует, что ваша система сможет получить доступ и установить последние пакеты PHP, доступные в PPA.
Вы можете переключаться между версиями PHP изменяя вашу переменную PATH
. Как альтернативу
вы можете использовать deb-sphp для автоматического переключения версии PHP.
Так же вы можете вручную переключаться между версиями PHP с помощью update-alternatives
на нужную версию:
sudo update-alternatives --set php /usr/bin/php8.2
sudo update-alternatives --set phar /usr/bin/phar8.2
sudo update-alternatives --set phar.phar /usr/bin/phar.phar8.2
Для дистрибутивов основанных на Debian, Ondřej Surý также bikeshed (Debian эквивалент PPA). Добавьте bikeshed в вашу ситему и обновите, следуя этим шагам:
Убедитесь что имеете root доступ. Если нет то возможно потребуется использование sudo
для выполнения следующих команд.
Обновите ваш список системных пакетов:
sudo apt-get update
Установите lsb-release
, ca-certificates
, и curl
:
sudo apt-get -y install lsb-release ca-certificates curl
Загрузите ключ подписи для репозитория:
sudo curl -sSLo /usr/share/keyrings/deb.sury.org-php.gpg https://packages.sury.org/php/apt.gpg
Добавьте репозиторий в источники программного обеспечения вашей системы:
sudo sh -c 'echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list'
Наконец, еще раз обновите список пакетов вашей системы:
sudo apt-get update
Выполнив эти шаги, ваша система сможет установить последние версии PHP-пакетов из bikeshed.
Распространенный вопрос среди тех кто начинает писать программы для Веб платформы, “куда положить мои вещи?” На
протяжении многих лет ответ был неизменным “туда где DocumentRoot
.” Хотя этот ответ и не полон, это отличное место
для начала.
По соображениям безопасности, у посетителей сайта не должно быть доступа к конфигурационным файлам; поэтому, публичные скрипты хранятся в публичной директории а приватные настройки и данные хранятся за пределами этой директории.
Для каждой команды, CMS или фреймворка, в котором он работает, каждый из этих объектов использует стандартную структуру каталогов. Однако, если вы начинаете проект в одиночку, знание того, какую структуру файловой системы использовать, может быть сложной задачей.
Paul M. Jones сделал несколько фантастических открытий общей практики из десятков тысяч github проектов PHP. Он
составил стандартную структуру файлов и каталогов Standard PHP Package Skeleton на основе этого исследования. В этой
структуре каталогов, DocumentRoot
должен указывать на public/
, unit-тесты должны быть в tests/
директории, а
сторонние библиотеки, установленные с помощью composer, принадлежат к vendor/
директории. Для остальных файлов и
каталогов, соблюдение Standard PHP Package Skeleton будет иметь больший смысл для участников проекта.
PHP сообщество многочисленно и разнообразно, состоящее из бесчисленных библиотек, фреймворков и компонентов. PHP разработчики обычно выбирают несколько из них и объединяют их в один проект. Важно, чтобы код PHP придерживался (как можно ближе) к общему стилю, чтобы разработчики могли легко смешивать и сопоставлять различные библиотеки для своих проектов.
Framework Interop Group предложил и одобрил серию рекомендаций по оформлению. Не все из них связаны со стилем кода, но те, что есть PSR-1, PSR-12, PSR-4 и PER Coding Style. Эти рекомендации представляют собой, просто набор правил, принятых во многих проектах, таких как Drupal, Zend, Symfony, Laravel, CakePHP, phpBB, AWS SDK, FuelPHP, Lithium, и т.д. Вы можете использовать их для своих собственных проектов, или продолжать использовать свой стиль.
В идеале вы должны писать PHP-код, соответствующий известному стандарту. Это может быть любая комбинация PSR или один из стандартов кодирования, разработанных PEAR или Zend. Это означает, что другие разработчики могут легко читать ваш код и работать с ним, а приложения, реализующие компоненты, могут иметь согласованность даже при работе с большим количеством стороннего кода.
Вы можете использовать PHP_CodeSniffer для проверки кода на соответствие любой из этих рекомендаций, а также плагины для текстовых редакторов таких как Sublime Text чтобы получать обратную связь в режиме реального времени.
Вы можете исправить макет кода автоматически, используя один из следующих инструментов.:
И вы можете запустить phpcs вручную из оболочки командной строки:
phpcs -sw --standard=PSR1 file.php
Оно покажет ошибки и расскажет, как их исправить.
Также может быть полезно включить команду phpcs
в git pre-commit hook с параметром коммандной строки --filter=GitStaged
.
Таким образом, код содержащий нарушения выбранного стандарта, не смогут войти в репозиторий, пока эти нарушения не
будут исправлены.
Если у вас есть PHP_CodeSniffer, вы можете автоматически исправить проблемы с макетом кода, о которых он сообщает, с помощью PHP Code Beautifier and Fixer.
phpcbf -w --standard=PSR1 file.php
Другим вариантом является использование PHP Coding Standards Fixer. Он покажет, какие ошибки были в структуре кода до их исправления.
php-cs-fixer fix -v --rules=@PSR1 file.php
Английский предпочтительнее для всех названий символов и кодовой инфраструктуры. Комментарии могут быть легко написаны на любом языке доступным для чтения всеми нынешними и будущими сторонами, которые могут работать над кодовой базой.
И наконец, хорошим дополнительным ресурсом для написания чистого PHP-кода является Clean Code PHP.
PHP гибкий, динамический язык который поддерживает различные техники программирования. Он резко эволюционировал на протяжении лет, в частности добавилась надежная объектно-ориентированная модель в PHP 5.0 (2004), анонимные функции и пространства имен в PHP 5.3 (2009), а так же трейты в PHP 5.4 (2012).
PHP имеет очень полный набор возможностей объектно-ориентированного программирования, включая поддержку классов, абстрактных классов, интерфейсов, наследования, конструкторов, клонирования, исключений и т. д.
PHP поддерживает первоклассные функции, имеется ввиду что функция может быть присвоена переменной. Функции определенные пользователем и встроенные функции, и те и другие могут ссылками переменной и вызываться динамически. Функции могут передаваться как аргументы других функций (особенность называется Higher-order Functions) и функции могут возвращать другие функции.
Рекурсия, особенность которая позволяет функции вызывать саму себя, она поддерживается языком, но большая часть PHP кода сфокусировано на итерациях.
Новые анонимные функции (которые поддерживают замыкания) представлены начиная с PHP 5.3 (2009).
PHP 5.4 добавлена возможность привязки замыканий к области видимости объекта а также улучшена поддержка для вызовов так что они могут быть взаимозаменяемо использованы с анонимными функциями почти во всех случаях.
call_user_func_array()
PHP поддерживает различные формы мета-программирования через механизмы такие как Reflection API и Магические Методы. Есть
много доступных Магических Методов как __get()
, __set()
, __clone()
, __toString()
, __invoke()
, и т.д. что
позволяют разработчикам подключаться к поведению класса. Разработчики Ruby часто говорят что PHP не хватает
method_missing
, но это доступно как __call()
и __callStatic()
.
Как было сказано выше, сообщество PHP состоит из большого количества разработчиков которые создают много кода. Это означает что код одной библиотеки PHP может использовать такое же имя класса как и в другой. Когда обе библиотеки используют одинаковые пространства имен, они сталкиваются и начинаются проблемы.
Пространства имен решают эту проблему. Как описано в PHP reference manual, пространства имен можно сравнить с каталогами операционной системы где namespace - файлы; два файла с одинаковыми именами могут сосуществовать в разных директориях. Также как, два PHP класса с одинаковыми именами могут сосуществовать в разных PHP пространствах имен. Это так же просто.
Важно использовать пространства имен для вашего кода, чтобы его могли использовать другие разработчики, не опасаясь конфликтов с другими библиотеками.
Один из рекомендуемых способов использования пространства имен описан в PSR-4, который нацелен на обеспечение стандарта согласования файла, класса и пространства имен позволяющих легко встраиваемый (plug-and-play) код.
В октябре 2014 PHP-FIG объявили устаревшим предыдущий стандарт автозагрузки: PSR-0. Оба PSR-0 и PSR-4 все еще вполне пригодны для использования. Последний требует PHP 5.3, и так много PHP 5.2-only проектов используют PSR-0.
Если вы собираетесь использовать стандарт автозагрузки в новых приложениях или пакетах, смотрите в сторону PSR-4.
Стандартная библиотека PHP (SPL) упакована вместе с PHP и предоставляет коллекции классов и интерфейсов. Это сделано в первую очередь для часто используемых структур данных классов (стек, очередь, куча, и т.д.), и итераторов которые могут проходить по этим структурам данных или вашим собственным классам которые предоставляют SPL интерфейсы.
PHP был создан чтобы писать веб-приложения, но он так же полезен для создания скриптовых программ с интерфейсом командной строки (CLI). Программы командной строки PHP могут помочь автоматизировать общие задачи такие как тестирование, разворачивание, и администрирование приложений.
Программы CLI PHP powerful потому что вы можете использовать код вашего приложения напрямую без необходимости создания и защиты графического веб-интерфейса для него. Просто убедитесь в том что не положили ваши CLI PHP скрипты в корень вашей общедоступной директории!
Попробуйте запустить PHP из командной строки:
Параметр -i
выведет на экран вашу конфигурацию PHP также как функция phpinfo()
.
Параметр -a
предоставляет интерактивную среду, похоже на ruby’s IRB или на интерактивную среду python. Есть также ряд
других полезных параметров командной строки.
Давайте напишем простую “Hello, $name” CLI программу. Попробуйте создать файл с именем hello.php
как показано ниже.
<?php
if ($argc !== 2) {
echo "Usage: php hello.php <name>" . PHP_EOL;
exit(1);
}
$name = $argv[1];
echo "Hello, $name" . PHP_EOL;
PHP установит две специальные переменные, основываясь на аргументах с которыми вы выполнили скрипт. $argc
-
это целочисленная переменная содержащая аргумент count (количество) и $argv
- это переменная - массив
содержащий значение value каждого из аргументов. Первый аргумент - это всегда имя файла PHP скрипта, в данном случае
hello.php
.
Выражение exit()
используется с не нулевым (non-zero) числом чтобы дать понять командной оболочке когда команда
завершилась неудачей. Обычно используемые коды выходов могут быть найдены здесь.
Чтобы запустить наш скрипт ниже, из командной строки:
Один из самых полезных инструментов при разработке программного обеспечения является правильный отладчик. Он позволяет отслеживать выполнение вашего кода и контролировать содержимое в стеке. Xdebug, отладчик PHP, может быть использован разными IDE для обеспечения точек останова и проверки стека. Также могут быть доступны такие инструменты как PHPUnit и KCacheGrind для выполнения анализа покрытия и профилирование кода.
Если вы оказались в безвыходной ситуации, готовы прибегнуть к var_dump()
/print_r()
, и все ещё не можете найти решения -
If you find yourself in a bind, willing to resort to var_dump()
/print_r()
, and you still can’t find the solution -
возможно, вам нужно использовать отладчик.
Установка Xdebug может быть сложной, но одна из самых важных особенностей это “Удалённая Отладка” - если вы разрабатываете код локально и потом тестируете это внутри виртуальной машины или на другом сервере, Удаленная Отладка это особенность которую вы захотите включить сразу.
Традиционно вы будете изменять файл Apache VHost или .htaccess со следующими значениями:
Свойства “remote host” и “remote port”, будут соответствовать вашему локальному компьютеру и порту, который вы настроили в своей среде IDE для прослушивания. Тогда вам просто нужно перевести вашу IDE в режим «прослушивания подключений» и загрузить URL-адрес:
http://your-website.example.com/index.php?XDEBUG_SESSION_START=1
Теперь ваша IDE будет перехватывать текущее состояние во время выполнения скрипта, позволяя вам устанавливать точки останова и проверять значения в памяти.
Графические отладчики упрощают пошаговое выполнение кода, проверку переменных и оценку кода в реальном времени. Многие IDE имеют встроенную или подключаемую поддержку графической отладки с помощью Xdebug. MacGDBp — это бесплатный автономный графический интерфейс Xdebug с открытым исходным кодом для macOS.
Существует множество PHP-библиотек, фреймворков и компонентов на выбор. Ваш проект, скорее всего, будет использовать несколько из них — это зависимости проекта. До недавнего времени в PHP не было хорошего способа управления этими зависимостями проекта. Даже если вы управляли ими вручную, вам все равно приходилось беспокоиться об автозагрузчиках. Это больше не проблема.
В настоящее время существует две основные системы управления пакетами для PHP — Composer и PEAR. Composer в настоящее время является самым популярным менеджером пакетов для PHP, однако долгое время PEAR был основным, используемым менеджером пакетов. Знать историю PEAR — хорошая идея, так как вы все равно можете найти упоминания о нем, даже если никогда им не пользовались.
Composer — рекомендуемый менеджер зависимостей для PHP. Перечислите зависимости вашего проекта в файле composer.json
и, с помощью нескольких простых команд Composer автоматически загрузит зависимости вашего проекта и настроит автозагрузку
для вас. Composer аналогичен NPM в мире node.js или Bundler в мире Ruby.
Существует множество библиотек PHP, совместимых с Composer и готовых к использованию в вашем проекте. Эти “пакеты” перечислены в Packagist, официальном репозитории совместимых с Composer библиотек PHP.
Самый безопасный способ скачать composer — это следовать официальной инструкции.
Оно будет проверять установщик на повреждения и подлинность.
Программа установки устанавливает двоичный файл composer.phar
в ваш текущий рабочий каталог.
Мы рекомендуем устанавливать Composer глобально (напр. единственная копия в /usr/local/bin
). Для этого выполните
следующую команду:
Примечание. Если вышеуказанное не удается из-за разрешений, добавьте префикс sudo
.
Чтобы запустить локально установленный Composer, вы должны использовать php composer.phar
, глобально - просто composer
.
Для пользователей Windows самый простой способ приступить к работе — использовать программу установки ComposerSetup,
которая выполняет глобальную установку и настраивает ваш $PATH
так, чтобы вы могли просто вызвать composer
из любой
директории в вашей командной строке.
Composer отслеживает зависимости вашего проекта в файле с именем composer.json
. Вы можете управлять этим вручную если
хотите, или использовать сам Composer. Команда composer require
добавляет зависимость проекта и если у вас нет файла
composer.json
, он будет создан. Вот пример, который добавляет Twig как зависимость вашего проекта.
В качестве альтернативы, команда composer init
поможет вам создать полный файл composer.json
для вашего проекта.
В любом случае, как только вы создали свой файл composer.json
, вы можете сказать Composer, чтобы он загрузил и
установил свои зависимости в каталог vendor/
. Это также относится к загруженным вами проектам, в которых уже есть файл
composer.json
:
Затем добавьте эту строку в основной файл PHP вашего приложения; это скажет PHP использовать автозагрузчик Composer для зависимостей вашего проекта.
Теперь вы можете использовать зависимости вашего проекта, и они будут автоматически загружаться по запросу.
Composer создает файл с именем composer.lock
, в котором хранится точная версия каждого пакета, загруженного при первом
запуске composer install
. Если вы делитесь своим проектом с другими, убедитесь, что файл composer.lock
включен, чтобы
при запуске composer install
они получили те же версии, что и вы.
Чтобы обновить свои зависимости, запустите composer update
. Не используйте composer update
при развертывании, а
только composer install
, иначе вы можете получить разные версии пакетов в рабочей среде.
Это наиболее полезно, когда вы гибко определяете требования к версии. Например, требование к версии ~1.8
означает
“все, что новее 1.8.0
, но меньше 2.0.x-dev
”. Вы также можете использовать подстановочный знак *
, как в 1.8.*
.
Теперь команда Composer composer update
обновит все ваши зависимости до самой новой версии, которая соответствует
ограничениям, которые вы определили.
Чтобы получать уведомления о новых выпусках версий, вы можете подписаться на libraries.io, веб-службу, которая может отслеживать зависимости и отправлять вам оповещения об обновлениях.
Local PHP Security Checker — это инструмент командной строки, который проверит ваш файл composer.lock
и сообщит, нужно ли вам обновить какие-либо из ваших зависимостей.
Composer также может обрабатывать глобальные зависимости и их двоичные файлы. Использование простое - все, что вам нужно сделать, это добавить к вашей команде префикс «global». Например, если вы хотите установить PHPUnit и сделать его доступным по всему миру, вы должны выполнить следующую команду:
Это создаст папку ~/.composer
, в которой находятся ваши глобальные зависимости. Чтобы бинарные файлы установленных
пакетов были доступны везде, вы должны добавить папку ~/.composer/vendor/bin
в свою переменную $PATH
.
Менеджер пакетов-ветеран, которым пользуются некоторые PHP-разработчики, называется PEAR. Он ведет себя аналогично Composer, но имеет некоторые заметные отличия.
PEAR требует, чтобы каждый пакет имел определенную структуру, а это означает, что автор пакета должен подготовить его для использования с PEAR. Использование проекта, не подготовленного для работы с PEAR, невозможно.
PEAR устанавливает пакеты глобально, что означает, что после их установки они становятся доступными для всех проектов на этом сервере. Это может быть хорошо, если многие проекты полагаются на один и тот же пакет с одной и той же версией, но может привести к проблемам, если между двумя проектами возникнут конфликты версий.
Вы можете установить PEAR, загрузив установщик .phar
и запустив его. В документации PEAR есть подробные
инструкции по установке для каждой операционной системы.
Если вы используете Linux, вы также можете взглянуть на менеджер пакетов вашего дистрибутива. Debian и Ubuntu, например, имеют подходящий пакет php-pear.
Если пакет указан в списке пакетов PEAR, вы можете установить его, указав официальное имя:
Если пакет размещен на другом канале, вам необходимо сначала «обнаружить» этот канал, а также указать его при установке. См. Использование документации канала для получения дополнительной информации по этой теме.
Если вы уже используете Composer и хотите также установить некоторый код PEAR, вы можете использовать Composer для обработки зависимостей PEAR. PEAR репозитории больше не поддерживаются напрямую Composer версии 2, так что вы должны вручную добавлять репозиторий для установки PEAR пакетов:
{
"repositories": [
{
"type": "package",
"package": {
"name": "pear2/pear2-http-request",
"version": "2.5.1",
"dist": {
"url": "https://github.com/pear2/HTTP_Request/archive/refs/heads/master.zip",
"type": "zip"
}
}
}
],
"require": {
"pear2/pear2-http-request": "*"
},
"autoload": {
"psr-4": {"PEAR2\\HTTP\\": "vendor/pear2/pear2-http-request/src/HTTP/"}
}
}
Первый раздел "repositories"
будет использоваться, чтобы сообщить Composer, что он должен “инициализировать”
(или “обнаружить” в терминологии PEAR) репозиторий pear. Затем раздел require
будет добавлять префикс к имени пакета
следующим образом:
pear-channel/package
Префикс “pear” жестко запрограммирован, чтобы избежать конфликтов, поскольку канал pear может быть таким же, как, например, имя поставщика другого пакета, тогда короткое имя канала (или полный URL-адрес) может использоваться для ссылки на канал, в котором находится пакет.
Когда этот код будет установлен, он будет доступен в вашем каталоге vendor и автоматически доступен через автозагрузчик Composer:
vendor/pear2/pear2-http-request/pear2/HTTP/Request.php
Чтобы использовать этот пакет PEAR, просто укажите его следующим образом:
<?php
require __DIR__ . '/vendor/autoload.php';
use PEAR2\HTTP\Request;
$request = new Request();
PHP — это обширный язык, который позволяет программистам всех уровней создавать код не только быстро, но и эффективно. Однако, продвигаясь по языку, мы часто забываем основы, которые мы сначала изучили (или упустили из виду), в пользу коротких путей и/или вредных привычек. Чтобы помочь справиться с этой распространенной проблемой, этот раздел призван напомнить программистам об основных методах кодирования в PHP.
В PHP есть класс DateTime, который поможет вам при чтении, записи, сравнении или вычислении даты и времени. Помимо DateTime, в PHP есть много функций, связанных с датой и временем, но он предоставляет хороший объектно-ориентированный интерфейс для наиболее распространенных применений. DateTime может обрабатывать часовые пояса, но это выходит за рамки этого краткого введения.
Чтобы начать работу с DateTime, преобразуйте необработанную строку даты и времени в объект с помощью фабричного метода
createFromFormat() или выполните команду new DateTime, чтобы получить текущую дату и время. Используйте метод format()
,
чтобы преобразовать DateTime обратно в строку для вывода.
<?php
$raw = '22. 11. 1968';
$start = DateTime::createFromFormat('d. m. Y', $raw);
echo 'Start date: ' . $start->format('Y-m-d') . PHP_EOL;
Вычисление с помощью DateTime возможно с классом DateInterval. DateTime имеет такие методы, как add()
и sub()
,
которые принимают DateInterval в качестве аргумента. Не пишите код, который ожидает одинаковое количество секунд каждый
день. И переход на летнее время, и изменение часового пояса нарушат это предположение. Вместо этого используйте интервалы
дат. Для вычисления разницы дат используйте метод diff()
. Он вернет новый DateInterval, который очень легко отобразить.
<?php
// create a copy of $start and add one month and 6 days
$end = clone $start;
$end->add(new DateInterval('P1M6D'));
$diff = $end->diff($start);
echo 'Difference: ' . $diff->format('%m month, %d days (total: %a days)') . PHP_EOL;
// Difference: 1 month, 6 days (total: 37 days)
Вы можете использовать стандартные сравнения объектов DateTime:
<?php
if ($start < $end) {
echo "Start is before the end!" . PHP_EOL;}
Последний пример для демонстрации класса DatePeriod. Он используется для повторения повторяющихся событий. Он может принимать два объекта DateTime, начало и конец, а также интервал, в течение которого он будет возвращать все промежуточные события.
<?php
// output all thursdays between $start and $end
$periodInterval = DateInterval::createFromDateString('first thursday');
$periodIterator = new DatePeriod($start, $periodInterval, $end, DatePeriod::EXCLUDE_START_DATE);
foreach ($periodIterator as $date) {
// output each date in the period
echo $date->format('Y-m-d') . ' ';
}
Популярным расширением PHP API является Carbon. Он наследует все в классе DateTime, поэтому требует минимальных изменений кода, но дополнительные функции включают поддержку локализации, дополнительные способы добавления, вычитания и форматирования объекта DateTime, а также средства для тестирования вашего кода путем имитации даты и времени по вашему выбору.
Когда вы создаете свое приложение, полезно использовать общие шаблоны в вашем коде и общие шаблоны для общей структуры вашего проекта. Использование общих шаблонов полезно, потому что это значительно упрощает управление вашим кодом и позволяет другим разработчикам быстро понять, как все сочетается друг с другом.
Если вы используете фреймворк, то большая часть кода более высокого уровня и структуры проекта будут основаны на этом фреймворке, поэтому многие решения по шаблонам принимаются за вас. Но выбор лучших шаблонов для кода, который вы строите поверх фреймворка, по-прежнему зависит от вас. Если, с другой стороны, вы не используете фреймворк для создания своего приложения, вам нужно найти шаблоны, которые лучше всего подходят для типа и размера приложения, которое вы создаете.
Вы можете узнать больше о шаблонах проектирования PHP и увидеть рабочие примеры по адресу:
Этот раздел был первоначально написан Alex Cabal по адресу Лучшие практики PHP и использовались в качестве основы для наших собственных рекомендаций по UTF-8.
В данный момент PHP не поддерживает Unicode на низком уровне. Есть несколько способов обеспечения корректной обработки строк UTF-8, но это не легко, и требуется копаться, почти во всех уровнях веб-приложения, начиная с HTML до SQL и PHP. Мы будем стремиться к краткому практическому изложению.
Базовые операции со строками, такие как конкатенация двух строк и присваивание строк к переменным, не требуют ничего
специально для UTF-8. Однако, большинство строковых функций, как strpos()
и strlen()
, требуют специальных решений.
Эти функции часто имеют приставку mb_*
: например, mb_strpos()
and mb_strlen()
. Эти mb_*
строки доступны вам через
Multibyte String Extension, и специально разработаны для операций со строками Unicode.
Вы должны использовать mb_*
функции каждый раз когда оперируете над Unicode строками. Например если вы будете
использовать substr()
с UTF-8 строкой, существует большой риск, того, что результат будет содержать некоторые
искаженные полу-символы. Правильной для использования функцией будет, мультибайтовая пара, mb_substr()
.
Сложная часть - постоянно помнить об использовании mb_*
функций. Если вы забудете даже один раз,ваша Unicode строка
имеет шанс быть искаженной при дальнейшей обработке.
Не все строковые функции имеют дополнение mb_*
. Если его нет, для того что вы хотите, тогда вам просто не повезло.
Необходимо использовать функцию mb_internal_encoding()
в начале каждого, написанного вами скрипта PHP (или в начале
глобально подключенного скрипта), и прямо следом функцию mb_http_output()
, если ваш скрипт выводится в браузер. Четкое
определение кодировки ваших скриптов спасет вас от большого количества головной боли.
Более того, многие PHP функции которые оперируют со строками имеют необязательный параметр, позволяющий вам определять
кодировку символа. Вы должны всегда четко указывать UTF-8, когда предоставляется возможность. Например, htmlentities()
имеет параметр для кодировки символа, и вы всегда должны указывать UTF-8, если имеете дело с такими строками. Обратите
внимание что начиная с PHP 5.4.0, UTF-8 кодировка по-умолчанию для htmlentities()
и htmlspecialchars()
.
И наконец, если вы создаете распространяемое приложение и не можете быть уверены что расширение mbstring
будет включено,
тогда рассмотрите использование symfony/polyfill-mbstring пакета Composer. Он будет использовать mbstring
, когда
доступно, и вернется к не UTF-8 функциям если нет.
Если ваш PHP скрипт обращается к MySQL, есть шанс что ваши строки будут храниться как не-UTF-8 строки в базе данных даже если вы следовали всем предостережениям выше.
Чтобы быть уверенным что ваши строки предаются от PHP к MySQL как UTF-8, убедитесь в том что ваша база данных и таблицы
установлены в utf8mb4
набор символов и сопоставление, и то что вы используете набор символов utf8mb4
в строке
подключения PDO. Смотрите пример ниже. Это критически важно.
Обратите внимание что вы должны использовать набор символов utf8mb4
для полноценной поддержки UTF-8, а не utf8
!
Смотрите дальнейшее чтение чтобы узнать почему.
Используйте mb_http_output()
функцию чтобы обеспечить UTF-8 вывод вашего PHP скрипта в браузер.
Затем браузер должен будет сообщить ответом HTTP, что эту страницу следует рассматривать как UTF-8. Сегодня принято устанавливать набор символов в заголовке ответа HTTP следующим образом:
<?php
header('Content-Type: text/html; charset=UTF-8')
Исторический подход к этому заключался в том, чтобы включить
тег charset <meta>
в тег <head>
вашей страницы.
<?php
// Tell PHP that we're using UTF-8 strings until the end of the script
mb_internal_encoding('UTF-8');
$utf_set = ini_set('default_charset', 'utf-8');
if (!$utf_set) {
throw new Exception('could not set default_charset to utf-8, please ensure it\'s set on your system!');
}
// Tell PHP that we'll be outputting UTF-8 to the browser
mb_http_output('UTF-8');
// Our UTF-8 test string
$string = 'Êl síla erin lû e-govaned vîn.';
// Transform the string in some way with a multibyte function
// Note how we cut the string at a non-Ascii character for demonstration purposes
$string = mb_substr($string, 0, 15);
// Connect to a database to store the transformed string
// See the PDO example in this document for more information
// Note the `charset=utf8mb4` in the Data Source Name (DSN)
$link = new PDO(
'mysql:host=your-hostname;dbname=your-db;charset=utf8mb4',
'your-username',
'your-password',
array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_PERSISTENT => false
)
);
// Store our transformed string as UTF-8 in our database
// Your DB and tables are in the utf8mb4 character set and collation, right?
$handle = $link->prepare('insert into ElvishSentences (Id, Body, Priority) values (default, :body, :priority)');
$handle->bindParam(':body', $string, PDO::PARAM_STR);
$priority = 45;
$handle->bindParam(':priority', $priority, PDO::PARAM_INT); // explicitly tell pdo to expect an int
$handle->execute();
// Retrieve the string we just stored to prove it was stored correctly
$handle = $link->prepare('select * from ElvishSentences where Id = :id');
$id = 7;
$handle->bindParam(':id', $id, PDO::PARAM_INT);
$handle->execute();
// Store the result into an object that we'll output later in our HTML
// This object won't kill your memory because it fetches the data Just-In-Time to
$result = $handle->fetchAll(\PDO::FETCH_OBJ);
// An example wrapper to allow you to escape data to html
function escape_to_html($dirty){
echo htmlspecialchars($dirty, ENT_QUOTES, 'UTF-8');
}
header('Content-Type: text/html; charset=UTF-8'); // Unnecessary if your default_charset is set to utf-8 already
?><!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>UTF-8 test page</title>
</head>
<body>
<?php
foreach($result as $row){
escape_to_html($row->Body); // This should correctly output our transformed UTF-8 string to the browser
}
?>
</body>
</html>
Предупреждение для новичков: i18n и l10n — это нумеронимы, своего рода аббревиатура, где числа используются для сокращения слов — в нашем случае интернационализация становится i18n, а локализация — l10n.
Прежде всего, нам нужно определить эти два похожих понятия и другие связанные вещи:
Самый простой способ интернационализировать софт PHP - это использование массива файлов и строк в шаблонах, таких как
<h1><?=$TRANS['title_about_page']?></h1>
. Однако, этот способ, вряд ли рекомендован для серьезных проектов, так как это
предполагает некоторые проблемы в обслуживании на пути - некоторые могут появиться в самом начале, такие как
множественность.Так что, пожалуйста, не пробуйте это, если ваш проект будет состоять из более чем пары страниц.
Самый классический и часто используемый способ для i18n и l10n - это Unix инструмент называющийся gettext
.
Он берет своё начало с 1995 и все еще является совершенной реализацией для перевода программного обеспечения. С ним
достаточно легко начать работать, пока все еще обладающий недюжинной силой, инструмент поддержки. О Gettext мы поговорим
здесь. Так же , чтобы помочь вам не запутаться в командной строке, мы представим замечательное GUI приложение которое
может быть использовано для легкого обновления вашего l10n исходника.
Есть общеиспользуемые библиотеки которые поддерживают Gettext и другие реализации i18n. Некоторые из них могут показаться более простыми в установке или поддержке дополнительных возможностей или i18n файловых форматов. В этом документе, мы фокусируемся на инструментах поставляемых с ядром PHP, но здесь, для полноты, мы перечислим и другие:
intl
расширение (включая множественные сообщения).gettext
), а также
экспорт в другие форматы помимо .mo/.po
файлов. Может быть полезно если нужно интегрировать ваши файлы перевода в другие
части системы, например JavaScript интерфейс.strtr()
.Другие фреймворки также включают в себя i18n модули, но они не доступны за пределами их кодовой базы:
@lang
для файлов шаблонов.Intl
, доступным, начиная с PHP 5.3, и основанным на ICU project; это позволяет Yii выполнять
мощные замены, такие как прописывание чисел, форматирование дат, времени, интервалов, валюты и порядковых номеров.Если вы решите использовать одну из библиотек, не предоставляющих экстракторов, вы можете использовать форматы gettext, чтобы вы могли использовать исходную цепочку инструментов gettext (включая Poedit), как описано в оставшейся части главы.
Возможно, вам потребуется установить Gettext и связанную с ним библиотеку PHP с помощью вашего менеджера пакетов, такого
как apt-get
или yum
. После установки включите его, добавив extension=gettext.so
(Linux/Unix) или
extension=php_gettext.dll
(Windows) в ваш php.ini
.
Здесь мы также будем использовать Poedit для создания файлов перевода. Вы, вероятно, найдете его в менеджере пакетов вашей системы; он доступен для Unix, macOS и Windows, а также может быть бесплатно загружен на их веб-сайте.
Есть три файла, с которыми вы обычно имеете дело при работе с gettext. Основными из них являются файлы PO (Portable Object) и MO (Machine Object), первый из которых представляет собой список читаемых «переведенных объектов», а второй — соответствующий двоичный файл, который должен интерпретироваться gettext при выполнении локализации. Существует также файл POT (шаблон), который просто содержит все существующие ключи из ваших исходных файлов и может использоваться в качестве руководства для создания и обновления всех файлов PO. Эти файлы шаблонов не являются обязательными: в зависимости от инструмента, который вы используете для выполнения l10n, вы вполне можете обойтись только файлами PO/MO. У вас всегда будет одна пара файлов PO/MO для каждого языка и региона, но только одна POT для каждого домена.
В некоторых случаях в больших проектах вам может понадобиться разделить переводы, когда одни и те же слова имеют разное значение в зависимости от контекста. В этих случаях вы разделяете их на разные домены. По сути, это именованные группы файлов POT/PO/MO, где имя файла является указанным доменом перевода. Малые и средние проекты обычно для простоты используют только один домен; его имя произвольное, но мы будем использовать «main» для наших примеров кода. Например, в проектах Symfony домены используются для разделения перевода сообщений проверки.
Locale - это просто код который идентифицирует версию одного языка. Это определено следующими ISO 639-1 и ISO 3166-1 alpha-2 спецификациями: две строчные буквы для языка, необязательно с последующим подчеркиванием и двумя заглавными буквами обозначающими код страны или региона. Для редких языков, используются три буквы.
Для некоторых говорящих часть страны может показаться избыточной. На самом деле некоторые языки имеют диалекты в разных
странах, например, австрийский немецкий (de_AT
) или бразильский португальский (pt_BR
). Вторая часть используется для
различия этих диалектов - когда ее нет, она рассматривается как «общая» или «гибридная» версия языка.
Чтобы использовать Gettext, нам нужно будет придерживаться определенной структуры папок. Во-первых, вам нужно будет выбрать
произвольный корень для ваших файлов l10n в исходном репозитории. Внутри у вас будет папка для каждой необходимой локали
и фиксированная папка LC_MESSAGES
, которая будет содержать все ваши пары PO/MO. Пример:
Как мы уже говорили во введении, разные языки могут иметь разные правила множественного числа. Однако gettext в очередной
раз спасает нас от этой неприятности. При создании нового файла .po
вам нужно будет объявить
правила множественного числа для этого языка, и переведенные части, чувствительные к множественному числу,
будут иметь другую форму для каждого из этих правил. При вызове Gettext в коде вам нужно будет указать номер, относящийся
к предложению, и он выработает правильную форму для использования - даже с использованием подстановки строк, если это
необходимо.
Правила множественного числа включают в себя количество доступных множественных чисел и логическую проверку с n
,
которая определяет, в какое правило попадает данное число (начиная с 0). Например:
nplurals=1; plural=0
- только одно правилоnplurals=2; plural=(n != 1);
- два правила, первое - если N единица, второе правило - в противном случаеnplurals=2; plural=(n > 1);
- два правила, второе - если N больше одного, первое - в противном
случаеТеперь, когда вы поняли, как работают правила множественного числа, а если нет, ознакомьтесь с более подробным объяснением в учебнике LingoHub, вы можете скопировать те, которые вам нужны, из списка вместо того, чтобы писать их от руки.
При вызове Gettext для локализации предложений со счетчиками вам также нужно будет указать соответствующий номер. Gettext
определит, какое правило должно действовать, и использует правильную локализованную версию. Вам нужно будет включить в
файл .po
разные предложения для каждого определенного правила множественного числа.
После всей этой теории давайте перейдем к практике. Вот выдержка из файла .po
- не обращайте внимания на его формат,
но вместо этого обратите внимание на общее содержание; позже вы научитесь легко его редактировать:
Первая секция работает как заголовок, имея пустые поля msgid
и msgstr
. В нем описывается кодировка файла,
формы множественного числа и другие менее важные вещи.
Второй раздел переводит простую строку с английского на
бразильский португальский, а третий делает то же самое, но использует замену строки из sprintf
, поэтому
перевод может содержать имя пользователя и дату посещения.
Последний раздел представляет собой пример форм множественного числа, отображающих
версию единственного и множественного числа как msgid
на английском языке и их соответствующие переводы как msgstr
0
и 1 (после числа, заданного правилом множественного числа). Там также используется замена строки, поэтому номер можно
увидеть прямо в предложении, используя %d
. Формы множественного числа всегда имеют два msgid
(единственное и
множественное число), поэтому рекомендуется не использовать сложный язык в качестве источника перевода.
Как вы могли заметить, мы используем в качестве идентификатора источника фактическое предложение на английском языке.
Этот msgid
используется во всех ваших файлах .po
, что означает, что другие языки будут иметь тот же формат и те же
поля msgid
, но переведенные строки msgstr
.
Говоря о ключах перевода, здесь есть две основные «школы»:
msgid
как настоящее предложение.
Основные преимущества:
msgid
;msgid
в нескольких языковых файлах.msgid
как уникальный, структурированный ключ.
Он будет структурированно описывать роль предложения в приложении, включая шаблон или часть, в которой находится строка,
а не ее содержимое.
en.po
, который переводчики
будут читать, чтобы понять, что писать, например, в fr.po
.top_menu.welcome
вместо Привет,
пользователь!
на указанной непереведенной французской странице). Это хорошо, поскольку заставило бы перевод быть
завершенным перед публикацией, но плохо, поскольку проблемы с переводом были бы ужасно ужасными в интерфейсе.
Некоторые библиотеки, тем не менее, включают возможность указать данный язык как “резервный”, имея поведение,
аналогичное другому подходу.В руководстве по Gettext предпочтение отдается первому подходу, так как в целом он проще для переводчиков и пользователей в случае возникновения проблем. Так же и здесь будем работать. Тем не менее, документация Symfony отдает предпочтение переводу на основе ключевых слов, что позволяет вносить независимые изменения во все переводы, не затрагивая при этом шаблоны.
В типичном приложении вы должны использовать некоторые функции Gettext при написании статического текста на своих
страницах. Затем эти предложения появляются в файлах .po
, переводятся, компилируются в файлы .mo
и затем используются
Gettext при рендеринге фактического интерфейса. Учитывая это, давайте свяжем то, что мы обсуждали до сих пор, в пошаговом
примере:
<?php include 'i18n_setup.php' ?>
<div id="header">
<h1><?=sprintf(gettext('Welcome, %s!'), $name)?></h1>
<!-- code indented this way only for legibility -->
<?php if ($unread): ?>
<h2><?=sprintf(
ngettext('Only one unread message',
'%d unread messages',
$unread),
$unread)?>
</h2>
<?php endif ?>
</div>
<h1><?=gettext('Introduction')?></h1>
<p><?=gettext('We\'re now translating some strings')?></p>
gettext()
просто переводит msgid
в соответствующий msgstr
для данного языка. Есть также короткая функция
_()
которая работает точно так же;ngettext()
делает то же самое, но с правилами множественного числа;dgettext()
и dngettext()
, что позволяют переопределить домен для одного вызова.
Подробнее о конфигурации домена в следующем примере.i18n_setup.php
, как указано выше), выбор правильной локали и настройка Gettext<?php
/**
* Verifies if the given $locale is supported in the project
* @param string $locale
* @return bool
*/
function valid($locale) {
return in_array($locale, ['en_US', 'en', 'pt_BR', 'pt', 'es_ES', 'es']);
}
//setting the source/default locale, for informational purposes
$lang = 'en_US';
if (isset($_GET['lang']) && valid($_GET['lang'])) {
// the locale can be changed through the query-string
$lang = $_GET['lang']; //you should sanitize this!
setcookie('lang', $lang); //it's stored in a cookie so it can be reused
} elseif (isset($_COOKIE['lang']) && valid($_COOKIE['lang'])) {
// if the cookie is present instead, let's just keep it
$lang = $_COOKIE['lang']; //you should sanitize this!
} elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
// default: look for the languages the browser says the user accepts
$langs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
array_walk($langs, function (&$lang) { $lang = strtr(strtok($lang, ';'), ['-' => '_']); });
foreach ($langs as $browser_lang) {
if (valid($browser_lang)) {
$lang = $browser_lang;
break;
}
}
}
// here we define the global system locale given the found language
putenv("LANG=$lang");
// this might be useful for date functions (LC_TIME) or money formatting (LC_MONETARY), for instance
setlocale(LC_ALL, $lang);
// this will make Gettext look for ../locales/<lang>/LC_MESSAGES/main.mo
bindtextdomain('main', '../locales');
// indicates in what encoding the file should be read
bind_textdomain_codeset('main', 'UTF-8');
// if your application has additional domains, as cited before, you should bind them here as well
bindtextdomain('forum', '../locales');
bind_textdomain_codeset('forum', 'UTF-8');
// here we indicate the default domain the gettext() calls will respond to
textdomain('main');
// this would look for the string in forum.mo instead of main.mo
// echo dgettext('forum', 'Welcome back!');
?>
Одним из больших преимуществ Gettext по сравнению с настраиваемыми пакетами i18n является обширный и мощный формат файлов. “О, чувак, это довольно сложно понять и отредактировать вручную, простой массив был бы проще!” Не заблуждайтесь, такие приложения, как Poedit, здесь, чтобы помочь - много. Вы можете скачать программу с их веб-сайта, она бесплатна и доступна для всех платформ. Это довольно простой инструмент, к которому можно привыкнуть, и в то же время очень мощный — он использует все функции, доступные в Gettext. Это руководство основано на PoEdit 1.8.
При первом запуске вы должны выбрать “File > New…” из меню. Вам сразу же будет предложено выбрать язык:
здесь вы можете выбрать/отфильтровать язык, на который хотите перевести, или использовать тот формат, который мы
упоминали ранее, например en_US
или pt_BR
.
Теперь сохраните файл, используя ту же структуру каталогов, о которой мы упоминали. Затем вы должны нажать “Extract from sources”, и здесь вы настроите различные параметры для задач извлечения и перевода. Вы сможете найти все это позже через “Catalog > Properties”:
gettext()
(и родственные) - обычно это
ваши папки шаблонов/представлений. Это единственная обязательная настройка;gettext()
и подобные вызовы функций выглядят в нескольких
языках программирования, но вы также можете создавать свои собственные функции перевода. Именно здесь вы добавите эти
другие методы. Об этом позже в разделе “Советы”.После установки этих точек он просканирует ваши исходные файлы, чтобы найти все вызовы локализации. После каждого сканирования PoEdit будет отображать сводку того, что было найдено и что было удалено из исходных файлов. Новые записи будут загружены в таблицу перевода пустыми, и вы начнете вводить локализованные версии этих строк. Сохраните его, и файл .mo будет (повторно)скомпилирован в ту же папку и та-да: ваш проект интернационализирован.
Как вы, возможно, уже заметили, есть два основных типа локализованных строк: простые и во множественном числе. Первые имеют просто два поля: исходную и локализованную строку. Исходная строка не может быть изменена, так как Gettext/Poedit не имеет права изменять ваши исходные файлы - вам следует изменить сам источник и повторно отсканировать файлы. Совет: вы можете щелкнуть правой кнопкой мыши строку перевода, и она подскажет вам исходные файлы и строки, в которых используется эта строка. С другой стороны, строки во множественном числе включают в себя два поля для отображения двух исходных строк и вкладки, позволяющие настраивать различные окончательные формы.
Всякий раз, когда вы изменяете свои источники и вам нужно обновить переводы, просто нажмите Refresh, и Poedit повторно просканирует код, удалив несуществующие записи, объединив те, которые были изменены, и добавив новые. Он также может попытаться угадать некоторые переводы, основываясь на других сделанных вами переводах. Эти предположения и измененные записи получат маркер “Fuzzy”, указывающий на то, что они нуждаются в проверке, и отобразятся в списке золотыми. Это также полезно, если у вас есть команда переводчиков, и кто-то пытается написать что-то, в чем он не уверен: просто отметьте Fuzzy, и кто-то другой проверит позже.
Наконец, рекомендуется оставить отмеченным “View > Untranslated entries first”, так как это поможет вам много не забыть, ни одной записи. Из этого меню вы также можете открывать части пользовательского интерфейса, которые позволяют при необходимости оставлять контекстную информацию для переводчиков.
Если вы используете PHP как модуль Apache (mod_php
), у вас могут возникнуть проблемы с кешированием файла .mo
.
Это происходит при первом чтении, а затем, чтобы обновить его, может потребоваться перезагрузка сервера. На Nginx и PHP5
обычно требуется всего пара обновлений страницы, чтобы обновить кеш перевода, а на PHP7 это требуется редко.
Многие предпочитают использовать _()
вместо gettext()
. Многие пользовательские библиотеки i18n из фреймворков также
используют что-то похожее на t()
, чтобы сделать переведенный код короче. Однако это единственная функция, которая имеет
ярлык. Возможно, вы захотите добавить в свой проект некоторые другие, такие как __()
или _n()
для ngettext()
, или,
может быть, причудливую _r()
, которая объединит вызовы gettext()
и sprintf()
. Другие библиотеки, такие как
php-gettext от Gettext, также предоставляют подобные вспомогательные функции.
В этих случаях, нужно дать инструкции Gettext утилите, как извлекать строки из этих новых функций.
Не бойтесь; это очень легко. Это просто поле в .po
файле, или экран Settings в Poedit. В редакторе, эта опция находится
внутри “Catalog > Properties > Source keywords”. Помните: Gettext уже знает функции по-умолчанию для многих языков, так
что не бойтесь, что этот список выглядит пустым. Необходимо включить там спецификации этих новых функций, следуя
определенному формату:
t()
это просто вернет перевод для строки, вы можете определить это как t
. Gettext
будет знать, что только аргумент функции - строка будет переведена;__('one user', '%d users', $number)
, спецификацией
будет __:1,2
, означает первая форма - это первый аргумент, и вторая форма - второй аргумент. Если вместо этого в
качестве первого аргумента используется ваше число, спецификация будет __:2,3
, что указывает на то, что первая форма
является вторым аргументом, и т.д.После включения этих новых правил в файл .po
, новое сканирование принесет ваши новые строки так же просто, как и раньше.
Из Wikipedia:
Внедрение зависимости - это шаблон проектирования ПО который позволяет устранение сложных зависимостей и делает возможным менять их, как в режиме реального времени так и на стадии компиляции.
Это высказывание делает концепцию более сложной, чем она на самом деле есть. Внедрение Зависимости предоставляет компонент с его зависимостями также через внедрение конструктора, вызовы метода или установку свойств. Это так легко.
Мы можем продемонстрировать концепцию, простым и примитивным примером.
У нас есть класс Database
, который требует адаптер для общения с базой данных.
Here we have a Database
class that requires an adapter to speak to the database. Мы реализуем адаптер в
конструкторе и создаем жесткую зависимость. Это делает тестирование сложным и означает что класс Database
, очень тесно
связан с адаптером.
<?php
namespace Database;
class Database
{
protected $adapter;
public function __construct()
{
$this->adapter = new MySqlAdapter;
}
}
class MysqlAdapter {}
Этот код может быть переработан с использованием Внедрения Зависимости и следовательно ослабит зависимости. Здесь мы внедряем зависимость в конструктор и используем продвижение свойства конструктора, для того, чтобы оно было доступно во всем классе:
<?php
namespace Database;
class Database
{
public function __construct(protected MySqlAdapter $adapter)
{
}
}
class MysqlAdapter {}
Теперь мы отдаем классу Database
его зависимость а не создаем его самого. Мы даже могли бы создать метод который принимал бы аргумент зависимости и устанавливал его этим способом, или если свойство $adapter
было public
, мы могли бы установить его напрямую.
Если вы когда либо читали о Внедрении зависимости, то вероятнее всего знакомы с терминами “Инверсия управления” или “Принцип инверсии зависимостей”. These are the complex problems that Dependency Injection solves.
Инверсия управления как говорится, “инвертирует управление” системы, сохраняя организационное управление полноценно отделяясь от наших объектов. В терминологии Инверсии управления, означает потерю наших зависимостей управляя и реализуя их где либо в системе.
На протяжении нескольких лет, PHP фреймворками была достигнута Инверсия Управления, однако, стоял вопрос, какую часть управления мы инвертируем, и где? Например, MVC фреймворки обычно предоставляют супер объект или, основной контроллер которые другие контроллеры должны расширять, получая доступ к их зависимостям. Это и есть Инверсия управления, однако, вместо потери зависимостей, этот метод просто перемещает их.
Внедрение зависимости позволяет нам более элегантно решить эту проблему, внедряя нужные зависимости, только тогда, когда мы нуждаемся в них, без необходимости сложных зависимостей вообще.
Принцип единственной ответственности об актерах и высокоуровневой архитектуре. Это состояние когда “Класс A должен иметь только одну причину для изменения.” Это значит, что каждый класс должен иметь ответственность только над одной частью функциональности предоставляемой ПО. Огромнейшая польза от этого подхода в том что он включает переиспользование улучшенного кода. Спроектировав наш класс для выполнения только одной задачи, мы можем использовать (или переиспользовать) его в любой другой программе, не изменяя.
Принцип открытости/закрытости касается проектирования классов и расширений функций. В нем говорится, что “программные объекты (классы, модули, функции и т. д.) должны быть открыты для расширения, но закрыты для модификации”. Это означает, что мы должны проектировать наши модули, классы и функции таким образом, чтобы, когда потребуется новая функциональность, мы не должны были изменять наш существующий код, а скорее писать новый код, который будет использоваться существующим кодом. С практической точки зрения это означает, что мы должны писать классы, которые реализуют интерфейсы и придерживаются их, а затем указывать тип для этих интерфейсов, а не для конкретных классов.
Самым большим преимуществом этого подхода является то, что мы можем очень легко расширить наш код с поддержкой чего-то нового, не изменяя существующий код, а это означает, что мы можем сократить время контроля качества, а риск негативного воздействия на приложение существенно снижается. Мы можем развертывать новый код быстрее и с большей уверенностью.
Принцип замены Лисков касается подтипов и наследования. В нем говорится, что “дочерние классы никогда не должны нарушать определения типов родительского класса”. Или, говоря словами Robert C. Martin, “подтипы должны быть взаимозаменяемыми для своих базовых типов”.
Например, если у нас есть интерфейс FileInterface
, который определяет метод embed()
, и у нас есть классы Audio
и
Video
, которые оба реализуют интерфейс FileInterface
, то мы можем ожидать, что использование Метод embed()
всегда
будет делать то, что мы намеревались. Если позже мы создадим класс PDF
или класс Gist
, которые реализуют интерфейс
FileInterface
, мы уже будем знать и понимать, что будет делать метод embed()
. Самым большим преимуществом этого
подхода является то, что у нас есть возможность создавать гибкие и легко настраиваемые программы, потому что, когда мы
меняем один объект типа (например, FileInterface
) на другой, нам не нужно ничего менять в нашей программе.
Принцип разделения интерфейса (ISP) касается связи бизнес-логики с клиентами. В нем говорится, что “Ни один клиент не должен зависеть от методов, которые он не использует”. Это означает, что вместо единого монолитного интерфейса, который должны реализовать все соответствующие классы, мы должны вместо этого предоставить набор меньших интерфейсов, зависящих от концепции, один или несколько из которых реализует соответствующий класс.
Например, классу Car
или Bus
будет интересен метод SteeringWheel()
, а классу Motorcycle
или Tricycle
— нет.
И наоборот, классу Motorcycle
или Tricycle
будет интересен метод handlebars()
, а классу Car
или Bus
— нет.
Нет необходимости, чтобы все эти типы транспортных средств поддерживали как steeringWheel()
, так и handlebars()
,
поэтому мы должны разделить исходный интерфейс.
Принцип инверсии зависимостей заключается в удалении жестких ссылок между отдельными классами, чтобы можно было использовать новые функции, передавая другой класс. В нем говорится, что нужно “Зависеть от абстракций. Не зависеть от конкретики”. Проще говоря, это означает, что наши зависимости должны быть интерфейсами/контрактами или абстрактными классами, а не конкретными реализациями. Мы можем легко реорганизовать приведенный выше пример, чтобы следовать этому принципу.
<?php
namespace Database;
class Database
{
public function __construct(protected AdapterInterface $adapter)
{
}
}
interface AdapterInterface {}
class MysqlAdapter implements AdapterInterface {}
Теперь у класса Database
есть несколько преимуществ, зависящих от интерфейса, а не от конкретизации.
Учтите, что мы работаем в команде, а над адаптером работает коллега. В нашем первом примере нам пришлось бы ждать, пока указанный коллега закончит работу над адаптером, прежде чем мы сможем должным образом смоделировать его для наших модульных тестов. Теперь, когда зависимость представляет собой интерфейс/контракт, мы можем с радостью создать макет этого интерфейса, зная, что наш коллега создаст адаптер на основе этого контракта.
Еще большее преимущество этого метода заключается в том, что наш код стал намного более масштабируемым. Если через год мы решим, что хотим перейти на базу данных другого типа, мы можем написать адаптер, который реализует исходный интерфейс и внедряет его вместо этого, больше не потребуется рефакторинг, поскольку мы можем гарантировать, что адаптер следует контракт, установленный интерфейсом.
Первая вещь которую вы должны понять о Контейнерах Внедрения Зависимостей, что они не тоже самое что и Внедрение Зависимости. Контейнер - это удобная утилита которая помогает нам реализовывать Внедрение Зависимости, более того, они могут быть и часто неправильно используются для реализации анти-паттерна, Служба Местоположения. Внедряет DI контейнер как Службу Локатор в ваши классы возможно создает сложную зависимость в контейнере чем зависимость которую вы заменяете. Также делает ваш код намного менее прозрачным и в конечном итоге более сложным для тестирования.
Самые современные фреймворки имеют свои собственные Контейнеры Внедрения Зависимостей которые позволяют вам соединять ваши зависимости вместе через конфигурацию. Что это значит на практике, то что вы можете писать код приложения, такой же чистый и разъединённый как это встроенно в фреймворках.
Много раз ваш PHP код будет использовать базу данных для хранения информации. У вас есть несколько способов соединения и взаимодействия с базой данных. Рекомендованным способом до PHP 5.1.0 было использование родных драйверов, таких как mysqli, pgsql, mssql, и т.д.
Родные драйверы хороши если вы используете только одну базу данных в вашем приложении, но если например, вы используете MySQL и немного MSSQL, или вам необходимо подключиться к базе данных Oracle, то тогда вы не сможете использовать одни и те же драйверы. Вам потребуется изучить новые фирменные API для каждой базы данных — и это может быть глупо.
Расширение mysql для PHP невероятно старое и было заменено двумя другими расширениями:
Разработка mysql была не только остановлена много лет назад но и была официально удалена в PHP 7.0.
Чтобы обезопасить вас от ковыряния в настройках php.ini
и увидеть какой модуль вы используете, один из вариантов,
воспользоваться поиском для mysql*
в вашем редакторе. Ели какая либо из функций таких как mysql_connect()
и
mysql_query()
появятся, то тогда mysql
используется.
Даже если вы еще не используете PHP 7.x или более позднии версии, позаботитесь об обновлении как можно скорее, иначе это приведет к большим трудностям, когда обновление PHP произойдет. Лучший вариант — заменить использование mysql на mysqli или PDO в своих приложениях в соответствии с собственным графиком разработки, чтобы потом не торопиться.
Если вы обновляетесь с mysql до mysqli, остерегайтесь ленивых руководств по обновлению, которые предлагают вам
просто найти и заменить mysql_*
на mysqli_*
. Это не только грубое упрощение, но и упущенные преимущества,
предоставляемые mysqli, такие как привязка параметров, которая также предлагается в PDO.
PDO — это библиотека абстракции подключения к базе данных — встроен в PHP начиная с версии 5.1.0 — который обеспечивает общий интерфейс для общения со многими различными базами данных. Например, вы можете использовать практически идентичный код для взаимодействия с MySQL или SQLite:
<?php
// PDO + MySQL
$pdo = new PDO('mysql:host=example.com;dbname=database', 'user', 'password');
$statement = $pdo->query("SELECT some_field FROM some_table");
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo htmlentities($row['some_field']);
// PDO + SQLite
$pdo = new PDO('sqlite:/path/db/foo.sqlite');
$statement = $pdo->query("SELECT some_field FROM some_table");
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo htmlentities($row['some_field']);
PDO не будет переводить ваши SQL-запросы или эмулировать отсутствующие функции; это исключительно для подключения к нескольким типам баз данных с одним и тем же API.
Что еще более важно, PDO
позволяет вам безопасно вводить чужие входные данные (например, ID) в ваши запросы SQL, не
беспокоясь об атаках путем внедрения SQL в базу данных. Это возможно с помощью операторов PDO и связанных параметров.
Предположим, PHP-скрипт получает числовой идентификатор в качестве параметра запроса. Этот идентификатор следует
использовать для извлечения записи пользователя из базы данных. Это wrong
способ сделать это:
<?php
$pdo = new PDO('sqlite:/path/db/users.db');
$pdo->query("SELECT name FROM users WHERE id = " . $_GET['id']); // <-- NO!
Это ужасный код. Вы вставляете необработанный параметр запроса в запрос SQL. Это позволит вам взломать систему в мгновение
ока, используя практику под названием SQL Инъекции. Только представьте, что хакер передает оригинальный параметр “id”,
вызывая URL-адрес типа http://domain.com/?id=1%3BDELETE+FROM+users
. Это установит для переменной $_GET['id']
значение
1;DELETE FROM users
, что удалит всех ваших пользователей! Вместо этого вы должны дезинфицировать ввод идентификатора,
используя параметры, привязанные к PDO.
<?php
$pdo = new PDO('sqlite:/path/db/users.db');
$stmt = $pdo->prepare('SELECT name FROM users WHERE id = :id');
$id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT); // <-- filter your data first
(see [Data Filtering](/php-the-right-way/#data_filtering)), especially important for INSERT, UPDATE, etc.
$stmt->bindParam(':id', $id, PDO::PARAM_INT); // <-- Automatically sanitized for SQL by PDO
$stmt->execute();
Это правильный код. Он использует связанный параметр в операторе PDO. Это ускользает от внешнего входного ID до того, как он будет введен в базу данных, предотвращая потенциальные атаки SQL-инъекций.
Для записей, таких как INSERT или UPDATE, особенно важно сначала по-прежнему фильтровать ваши данные и очищать их для других вещей (удаление HTML-тегов, JavaScript и т. д.). PDO будет очищать его только для SQL, а не для вашего приложения.
Вы также должны знать, что соединения с базой данных используют ресурсы, и не было ничего необычного в исчерпании ресурсов, если соединения не были неявно закрыты, однако это было более распространено в других языках. Используя PDO, вы можете неявно закрыть соединение, уничтожив объект, убедившись, что все оставшиеся ссылки на него удалены, т.е. установлены в NULL. Если вы не сделаете это явно, PHP автоматически закроет соединение, когда ваш сценарий завершится - если, конечно, вы не используете постоянные соединения.
Когда разработчики впервые начинают изучать PHP, они часто заканчивают тем, что смешивают взаимодействие с базой данных с логикой представления, используя код, который может выглядеть следующим образом:
<ul>
<?php
foreach ($db->query('SELECT * FROM table') as $row) {
echo "<li>".$row['field1']." - ".$row['field1']."</li>";
}
?>
</ul>
Это плохая практика по разным причинам, в основном из-за того, что ее трудно отлаживать, трудно тестировать, трудно читать, и она будет выводить много полей, если вы не установите там ограничение.
Хотя есть много других решений для этого — в зависимости от того, предпочитаете ли вы ООП или функциональное программирование — должен быть какой-то элемент разделения.
<?php
function getAllFoos($db) {
return $db->query('SELECT * FROM table');
}
$results = getAllFoos($db);
foreach ($results as $row) {
echo "<li>".$row['field1']." - ".$row['field1']."</li>"; // BAD!!
}
Это хорошее начало. Поместите эти два элемента в два разных файла, и вы получите четкое разделение.
Создайте класс для размещения этого метода, и у вас есть “Модель”. Создайте простой файл .php
, чтобы поместить в него
логику представления, и у вас будет “Представление”, которое очень близко к [MVC] - общей архитектуре ООП для большинства
фреймворков.
foo.php
<?php
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8mb4', 'username', 'password');
// Make your model available
include 'models/FooModel.php';
// Create an instance
$fooModel = new FooModel($db);
// Get the list of Foos
$fooList = $fooModel->getAllFoos();
// Show the view
include 'views/foo-list.php';
models/FooModel.php
<?php
class FooModel
{
public function __construct(protected PDO $db)
{
}
public function getAllFoos() {
return $this->db->query('SELECT * FROM table');
}
}
views/foo-list.php
<?php foreach ($fooList as $row): ?>
<li><?= $row['field1'] ?> - <?= $row['field1'] ?></li>
<?php endforeach ?>
По сути, это то же самое, что и большинство современных фреймворков, хотя и немного более ручное. Возможно, вам не нужно делать все это каждый раз, но смешивание слишком большого количества логики представления и взаимодействия с базой данных может стать реальной проблемой, если вы когда-нибудь захотите unit-тестирование своего приложения.
Многие фреймворки предоставляют свой собственный уровень абстракции, который может располагаться или не располагаться поверх PDO. Они часто будут эмулировать функции одной системы баз данных, отсутствующие в другой, оборачивая ваши запросы в методы PHP, предоставляя вам реальную абстракцию базы данных, а не просто абстракцию соединения, которую предоставляет PDO. Это, конечно, добавит немного накладных расходов, но если вы создаете переносимое приложение, которое должно работать с MySQL, PostgreSQL и SQLite, то небольшие накладные расходы будут оправданы ради чистоты кода.
Некоторые уровни абстракции были построены с использованием стандартов пространств имен PSR-0 или PSR-4, поэтому их можно установить в любое приложение, которое вам нравится:
Шаблоны обеспечивают удобный способ отделения логики контроллера и домена от логики представления. Шаблоны обычно содержат HTML-код вашего приложения, но могут также использоваться для других форматов, таких как XML. Шаблоны часто называют “представлениями”, которые составляют часть второго компонента model-view-controller (MVC) шаблон архитектуры программного обеспечения.
Основным преимуществом использования шаблонов является четкое разделение, которое они создают между логикой представления и остальной частью вашего приложения. Шаблоны несут исключительную ответственность за отображение форматированного контента. Они не несут ответственности за поиск данных, сохранение или другие более сложные задачи. Это приводит к более чистому и удобочитаемому коду, что особенно полезно в командной среде, где разработчики работают над кодом на стороне сервера (контроллеры, модели), а дизайнеры работают над кодом на стороне клиента (разметкой).
Шаблоны также улучшают организацию кода представления. Шаблоны обычно помещаются в папку «представления», каждый из которых определяется в одном файле. Этот подход поощряет повторное использование кода, когда большие блоки кода разбиваются на более мелкие повторно используемые части, часто называемые частичными. Например, верхний и нижний колонтитулы вашего сайта могут быть определены как шаблоны, которые затем включаются до и после каждого шаблона страницы.
Наконец, в зависимости от библиотеки, которую вы используете, шаблоны могут обеспечить большую безопасность, автоматически скрывая пользовательский контент. Некоторые библиотеки даже предлагают песочницу, где разработчикам шаблонов предоставляется доступ только к переменным и функциям из белого списка.
Простые шаблоны PHP — это просто шаблоны, в которых используется собственный код PHP. Это естественный выбор, поскольку PHP сам по себе является языком шаблонов. Это просто означает, что вы можете комбинировать PHP-код с другим кодом, например HTML. Это выгодно для PHP-разработчиков, так как нет необходимости изучать новый синтаксис, они знают доступные им функции, а их редакторы кода уже имеют встроенную подсветку синтаксиса PHP и автодополнение. Кроме того, простые шаблоны PHP, как правило, работают очень быстро, так как не требуют этапа компиляции.
Каждый современный PHP-фреймворк использует какую-то систему шаблонов, большинство из которых по умолчанию использует простой PHP. Вне фреймворков такие библиотеки, как Plates или Aura.View, упрощают работу с простыми шаблонами PHP, предлагая современные функции шаблонов, такие как наследование, макеты и расширения.
Использование библиотеки Plates.
<?php // user_profile.php ?>
<?php $this->insert('header', ['title' => 'User Profile']) ?>
<h1>User Profile</h1>
<p>Hello, <?=$this->escape($name)?></p>
<?php $this->insert('footer') ?>
Использование библиотеки Plates.
<?php // template.php ?>
<html>
<head>
<title><?=$title?></title>
</head>
<body>
<main>
<?=$this->section('content')?>
</main>
</body>
</html>
<?php // user_profile.php ?>
<?php $this->layout('template', ['title' => 'User Profile']) ?>
<h1>User Profile</h1>
<p>Hello, <?=$this->escape($name)?></p>
Хотя PHP превратился в зрелый объектно-ориентированный язык, он не сильно улучшился как язык шаблонов. Скомпилированные шаблоны, такие как Twig, Brainy или Smarty*, заполняют этот пробел, предлагая новый синтаксис, специально предназначенный для создания шаблонов. От автоматического экранирования до наследования и упрощенных структур управления — скомпилированные шаблоны разработаны так, чтобы их было проще писать, чище читать и безопаснее использовать. Скомпилированные шаблоны можно даже использовать на разных языках, Mustache является хорошим примером этого. Поскольку эти шаблоны должны быть скомпилированы, производительность снижается незначительно, однако при правильном кэшировании это минимально.
*Хотя Smarty предлагает автоматическое экранирование, эта функция НЕ включена по умолчанию.
Использование библиотеки Twig.
Использование библиотеки Twig.
Во многих языках программирования с большим количеством исключений всякий раз, когда что-то пойдет не так, будет выдано исключение. Это, безусловно, жизнеспособный способ сделать что-то, но PHP — это язык программирования с “легким исключением”. Хотя у него есть исключения, и большая часть ядра начинает использовать их при работе с объектами, большая часть самого PHP будет пытаться продолжать обработку независимо от того, что происходит, если только не произойдет фатальная ошибка.
Например:
Это всего лишь ошибка уведомления, и PHP с радостью продолжит работу. Это может сбивать с толку тех, кто работает с языками с “тяжелыми исключениями”, потому что, например, ссылка на отсутствующую переменную в Python вызовет исключение:
Единственная реальная разница в том, что Python сходит с ума из-за любой мелочи, так что разработчики могут быть уверены, что любая потенциальная проблема или пограничный случай обнаружены, в то время как PHP продолжит обработку, если не произойдет что-то экстремальное, и в этот момент он выдаст ошибку. ошибка и сообщите об этом.
PHP имеет несколько уровней серьезности ошибок. Тремя наиболее распространенными типами сообщений являются ошибки,
уведомления и предупреждения. Они имеют разные уровни серьезности; E_ERROR
, E_NOTICE
и E_WARNING
. Ошибки — это
фатальные ошибки во время выполнения, обычно они вызваны ошибками в вашем коде и должны быть исправлены, поскольку они
приводят к остановке выполнения PHP. Уведомления — это консультативные сообщения, вызванные кодом, который может вызывать
или не вызывать проблемы во время выполнения скрипта, выполнение не останавливается. Предупреждения являются не фатальными
ошибками, выполнение скрипта не будет остановлено.
Другим типом сообщений об ошибках, сообщаемых во время компиляции, являются сообщения E_STRICT
. Эти сообщения
используются для предложения изменений в вашем коде, чтобы обеспечить наилучшее взаимодействие и совместимость с будущими
версиями PHP.
Изменение поведения отчетов об ошибках PHP Отчеты об ошибках можно изменить с помощью настроек PHP и/или вызовов функций
PHP. Используя встроенную функцию PHP error_reporting()
, вы можете установить уровень ошибок на время выполнения
скрипта, передав одну из предопределенных констант уровня ошибок, что означает, что если вы хотите видеть только ошибки
и предупреждения, но не уведомления - то вы можете настроить это:
<?php
error_reporting(E_ERROR | E_WARNING);
Вы также можете контролировать, будут ли ошибки отображаться на экране (удобно для разработки) или скрыты и зарегистрированы (удобно для производства). Дополнительную информацию об этом можно найти в разделе Отчеты об ошибках.
Вы также можете указать PHP подавлять определенные ошибки с помощью оператора контроля ошибок @
. Вы помещаете этот
оператор в начало выражения, и любая ошибка, являющаяся прямым результатом выражения, замалчивается.
<?php
echo @$foo['bar'];
Это выведет $foo['bar']
, если он существует, но просто вернет null и ничего не напечатает, если переменная $foo
или
ключ 'bar'
не существует. Без оператора контроля ошибок это выражение могло бы создать ошибку PHP Notice: Undefined
variable:foo
или PHP Notice: Undefined index: bar
.
Это может показаться хорошей идеей, но есть несколько нежелательных компромиссов. PHP обрабатывает выражения, использующие
@
, менее эффективно, чем выражения без @
. Преждевременная оптимизация может быть корнем всех аргументов
программирования, но если производительность особенно важна для вашего приложения/библиотеки, важно понимать влияние
оператора контроля ошибок на производительность.
Во-вторых, оператор контроля ошибок полностью проглатывает ошибку. Ошибка не отображается, и ошибка не отправляется в журнал ошибок. Кроме того, стандартные / производственные PHP-системы не имеют возможности отключить оператор контроля ошибок. Хотя вы можете быть правы в том, что ошибка, которую вы видите, безобидна, другая, менее безобидная ошибка будет такой же бесшумной.
Если есть способ избежать оператора подавления ошибок, вы должны рассмотреть его. Например, наш код выше можно было бы переписать так:
<?php
// Null Coalescing Operator
echo $foo['bar'] ?? '';
Один из случаев, когда подавление ошибок может иметь смысл, это когда fopen()
не может найти файл для загрузки. Вы
можете проверить существование файла, прежде чем пытаться его загрузить, но если файл будет удален после проверки и до
fopen()
(что может показаться невозможным, но это может случиться), тогда fopen()
вернет false и выдаст ошибку.
Этот потенциально это то, что PHP должен решить, но это один из случаев, когда подавление ошибок может показаться
единственным правильным решением.
Ранее мы упоминали, что в стандартной системе PHP нет возможности отключить оператор контроля ошибок. Однако Xdebug
имеет ini-настройку xdebug.scream
, которая отключает оператор контроля ошибок. Вы можете установить это через файл
php.ini
следующим образом.
Вы также можете установить это значение во время выполнения с помощью функции ini_set
<?php
ini_set('xdebug.scream', '1')
Это наиболее полезно, когда вы отлаживаете код и подозреваете, что информационная ошибка подавляется. Используйте scream с осторожностью и как временный инструмент отладки. Есть много кода библиотеки PHP, который может не работать с отключенным оператором контроля ошибок.
PHP способен быть ”насыщенным исключениями” языком программирования, и для переключения требуется всего несколько строк
кода. В основном вы можете бросать ваши “ошибки” как “исключения” используя класс ErrorException
, который расширяет
класс Exception
.
Эта общая практика реализована большим количеством современных фреймворков, таких как Symfony и Laravel. В режиме отладки (или режиме разработки) оба этих фреймворка будут отображать хорошие и понятные трассировки стека.
Также есть несколько доступных пакетов для улучшенной обработки и отчетности ошибок и исключений. Как Whoops!, который идет вместе с установкой Laravel по-умолчанию, и может быть использован вообще с любым фреймворком.
Выкидывая ошибки как исключения при разработке, вы можете обрабатывать их лучше чем обычной ситуации, и если вы видите исключение во время разработки, вы можете оборачивать его в конструкцию catch с определенными инструкциями о том как обработать ситуацию. Каждое исключение которое вы мгновенно отлавливаете, делает ваше приложение немного более надежным.
Больше подробной информации об этом и о том как использовать ErrorException
для обработки ошибок можно найти по ссылкам
ErrorException Class.
Исключения являются стандартной частью большинства популярных языков программирования, но PHP-программисты часто упускают их из виду.
Такие языки, как Ruby, очень сильно насыщенны исключениями, поэтому всякий раз, когда что-то идет не так, например, сбой HTTP-запроса или запрос БД, или даже если ресурс изображения не может быть найден, Ruby (или используемые gems) выдает исключение на экран, что означает, что вы сразу узнаете, что произошла ошибка.
PHP сам по себе довольно слаб с этим, и вызов file_get_contents()
обычно просто дает вам FALSE
и предупреждение.
Многие старые PHP-фреймворки, такие как CodeIgniter, просто вернут false, запишут сообщение в свои проприетарные журналы
и, возможно, позволят вам использовать такой метод, как $this->upload->get_error()
, чтобы увидеть, что пошло не так.
Проблема здесь в том, что вам нужно искать ошибку и проверять документы, чтобы увидеть, какой метод ошибки используется
для этого класса, вместо того, чтобы делать это предельно очевидным.
Другая проблема — когда классы автоматически выбрасывают ошибку на экран и выходят из процесса. Когда вы делаете это, вы мешаете другому разработчику динамически обрабатывать эту ошибку. Исключения должны создаваться, чтобы разработчики знали об ошибке; затем они могут выбрать, как с этим справиться. Например.:
<?php
$email = new Fuel\Email;
$email->subject('My Subject');
$email->body('How the heck are you?');
$email->to('guy@example.com', 'Some Guy');
try
{
$email->send();
}
catch(Fuel\Email\ValidationFailedException $e)
{
// The validation failed
}
catch(Fuel\Email\SendingFailedException $e)
{
// The driver could not send the email
}
finally
{
// Executed regardless of whether an exception has been thrown, and before normal execution resumes
}
Общий класс Exception
предоставляет разработчику очень мало контекста отладки; однако, чтобы исправить это, можно
создать специализированный тип Exception
, создав подкласс общего класса Exception
:
<?php
class ValidationException extends Exception {}
Это означает, что вы можете добавить несколько блоков catch и по-разному обрабатывать разные исключения. Это может привести к созданию множества пользовательских исключений, некоторых из которых можно было бы избежать с помощью исключений SPL, представленных в расширении SPL.
Если, например, вы используете магический метод __call()
и запрошен недопустимый метод, то вместо того, чтобы
генерировать стандартное исключение, которое является расплывчатым, или создавать специальное исключение только для этого,
вы можете просто throw new BadMethodCallException;
.
Лучшие ресурсы которые я нашел по PHP безопасности The 2018 Guide to Building Secure PHP Software by Paragon Initiative.
Очень важно для каждого разработчика PHP изучить основы безопасности веб-приложений, которые можно разбить на несколько широких тем:
Есть плохие люди, готовые и желающие использовать ваше веб-приложение. Важно, чтобы вы приняли необходимые меры предосторожности для повышения безопасности вашего веб-приложения. К счастью, замечательные люди из The Open Web Application Security Project (OWASP) составили исчерпывающий список известных проблем с безопасностью и способы защиты от них. Это необходимо прочитать разработчику, заботящемуся о безопасности. Survive The Deep End: PHP Security Padraic Brady — еще одно хорошее руководство по безопасности веб-приложений для PHP.
В конце концов каждый создает приложение PHP, которое зависит от входа пользователя в систему. Имена пользователей и пароли хранятся в базе данных и позже используются для аутентификации пользователей при входе в систему.
Важно, чтобы вы правильно делали hash паролей перед их сохранением. Хеширование и шифрование — это две очень разные вещи, которые часто путают.
Хеширование — необратимая односторонняя функция. Это создает строку фиксированной длины, которую невозможно обратить вспять. Это означает, что вы можете сравнить хэш с другим, чтобы определить, пришли ли они оба из одной и той же исходной строки, но вы не можете определить исходную строку. Если пароли не хэшируются и к вашей базе данных обращается неавторизованная третья сторона, все учетные записи пользователей теперь скомпрометированы.
В отличие от хеширования, шифрование обратимо (если у вас есть ключ). Шифрование полезно в других областях, но это плохая стратегия для безопасного хранения паролей.
Пароли также должны быть индивидуально salted путем добавления случайной строки к каждому паролю перед хешированием. Это предотвращает атаки по словарю и использование «радужных таблиц» (обратный список криптографических хэшей для обычных паролей).
Хеширование и добавление соли жизненно важны, так как часто пользователи используют один и тот же пароль для нескольких сервисов, а качество пароля может быть низким.
Кроме того, вам следует использовать специализированный алгоритм_хеширования_пароля, а не быструю универсальную криптографическую хеш-функцию (например, SHA256). Краткий список приемлемых алгоритмов хеширования паролей (по состоянию на июнь 2018 г.) для использования:
К счастью, в настоящее время PHP делает это легко.
Хеширование паролей с password_hash
В PHP 5.5 был введен password_hash()
. В настоящее время он использует BCrypt, самый сильный алгоритм, который в
настоящее время поддерживается PHP. Однако в будущем он будет обновлен для поддержки большего количества алгоритмов по
мере необходимости. Библиотека password_compat
была создана для обеспечения прямой совместимости с PHP >= 5.3.7.
Ниже мы хешируем строку, а затем проверяем хеш на новую строку. Поскольку наши две исходные строки различаются (“secret-password” и “bad-password”), этот вход не удастся.
<?php
require 'password.php';
$passwordHash = password_hash('secret-password', PASSWORD_DEFAULT);
if (password_verify('bad-password', $passwordHash)) {
// Correct Password
} else {
// Wrong password
}
password_hash()
позаботится о добавлении соли для вас. Соль хранится вместе с алгоритмом и “расценивается” как часть
хэша. password_verify()
извлекает это, чтобы определить, как проверить пароль, поэтому вам не нужно отдельное поле
базы данных для хранения ваших солей.
Никогда (никогда) не доверяйте чужому вводу, введенному в ваш PHP-код. Всегда очищайте и проверяйте внешний ввод перед
его использованием в коде. Функции filter_var()
и filter_input()
могут очищать текст и проверять текстовые форматы
(например, адреса электронной почты).
Внешний ввод может быть любым: $_GET
и $_POST
формируют входные данные, некоторые значения в суперглобальном массиве
$_SERVER
и тело HTTP-запроса через fopen('php://input', 'r')
. Помните, что внешний ввод не ограничивается данными
формы, отправленными пользователем. Загруженные и выгруженные файлы, значения сеанса, данные cookie и данные сторонних
веб-сервисов также являются посторонними входными данными.
Хотя сторонние данные можно хранить, комбинировать и обращаться к ним позже, они по-прежнему являются внешними входными данными. Каждый раз, когда вы обрабатываете, выводите, объединяете или включаете данные в свой код, спрашивайте себя, правильно ли фильтруются данные и можно ли им доверять.
Данные могут фильтроваться по-разному в зависимости от их назначения. Например, когда нефильтрованный посторонний ввод
передается в вывод HTML-страницы, он может выполнять HTML и JavaScript на вашем сайте! Это известно как межсайтовый
скриптинг (XSS) и может быть очень опасной атакой. Один из способов избежать XSS — очистить все пользовательские данные
перед их выводом на вашу страницу, удалив теги HTML с помощью функции strip_tags()
или экранировав символы со
специальным значением в соответствующие объекты HTML с помощью htmlentities()
или функции htmlspecialchars()
.
Другой пример — передача параметров для выполнения в командной строке. Это может быть чрезвычайно опасно (и, как правило,
это плохая идея), но вы можете использовать встроенную функцию escapeshellarg()
для очистки аргументов выполняемой
команды.
Последний пример — прием внешнего ввода для определения файла для загрузки из файловой системы. Это можно использовать,
изменив имя файла на путь к файлу. Вам нужно удалить "/"
, "../"
, null bytes или другие символы из пути к файлу,
чтобы он не мог загружать скрытые, непубличные или конфиденциальные файлы.
filter_var()
filter_input()
Очищение удаляет (или экранирует) недопустимые или небезопасные символы из внешнего ввода.
Например, вам необходимо очистить чужой ввод, прежде чем подключать ввод в HTML или вставлять его в необработанный SQL запрос. Когда вы используете связанные параметры с PDO, оно будет обеззараживать ввод для вас.
Иногда требуется разрешить несколько безопасных HTML тегов на входе, когда вкладываете их в HTML страницу. Это очень сложно сделать и многие избегают этого, используя более ограниченное форматирование, такое как Markdown или BBCode, хотя библиотеки белого списка, такие как HTML Purifier существуют по этой причине.
Опасно unserialize()
данные от пользователей или других недоверенных ресурсов
Опасно unserialize()
данные от пользователей или других ненадежных источников. Это может позволить злоумышленникам
создавать экземпляры объектов (с определяемыми пользователем свойствами), чьи деструкторы будут выполняться, даже если
сами объекты не используются. Поэтому вам следует избегать десериализации ненадежных данных.
Bспользуйте безопасный стандартный формат обмена данными, такой как JSON (через json_decode
и json_encode
), если вам нужно передать пользователю сериализованные данные.
Валидация гарантирует, что иностранный ввод соответствует вашим ожиданиям. Например, вы можете захотеть подтвердить адрес электронной почты, номер телефона или возраст при обработке заявки на регистрацию.
При создании файлов конфигурации для ваших приложений рекомендуется использовать один из следующих методов:
.php
. Это
гарантирует, что даже при прямом доступе к сценарию он не будет выводиться в виде обычного текста.ПРИМЕЧАНИЕ: Начиная с PHP 5.4.0 параметр register_globals был удален и больше не может использоваться. Это включено только в качестве предупреждения для всех, кто находится в процессе обновления устаревшего приложения.
Когда параметр конфигурации register_globals
включен, он делает несколько типов переменных (включая переменные из
$_POST
, $_GET
и $_REQUEST
) доступными в глобальной области вашего приложения. Это может легко привести к проблемам
с безопасностью, поскольку ваше приложение не может эффективно определить, откуда поступают данные.
Например: $_GET['foo']
будет доступен через $foo
, который может переопределять объявленные переменные.
Если вы используете PHP < 5.4.0, убедитесь, что функция register_globals
выключена.
Регистрация ошибок может быть полезна для поиска проблемных мест в вашем приложении, но она также может предоставить информацию о структуре вашего приложения для внешнего мира. Чтобы эффективно защитить ваше приложение от проблем, которые могут быть вызваны выводом этих сообщений, вам необходимо по-разному настроить сервер для разработки и производства (в реальном времени).
Чтобы показать все возможные ошибки во время разработки, настройте следующие параметры в файле php.ini
:
display_errors = On
display_startup_errors = On
error_reporting = -1
log_errors = On
Передача значения
-1
покажет все возможные ошибки, даже если в будущих версиях PHP будут добавлены новые уровни и константы. КонстантаE_ALL
также ведет себя так, начиная с PHP 5.4. - php.net
Константа уровня ошибки E_STRICT
была введена в 5.3.0 и не является частью E_ALL
, однако она стала частью E_ALL
в
5.4.0. Что это значит? С точки зрения сообщения о каждой возможной ошибке в версии 5.3 это означает, что вы должны
использовать либо -1
, либо E_ALL | E_STRICT
.
Отчет о каждой возможной ошибке по версии PHP
-1
or E_ALL
-1
or E_ALL | E_STRICT
-1
or E_ALL
Чтобы скрыть ошибки в вашей производственной среде, настройте файл php.ini
следующим образом:
display_errors = Off
display_startup_errors = Off
error_reporting = E_ALL
log_errors = On
При использовании этих настроек ошибки по-прежнему будут регистрироваться в журналах ошибок веб-сервера, но не будут отображаться пользователю. Дополнительные сведения об этих настройках см. в руководстве по PHP:
Написание автоматических тестов для вашего PHP-кода считается лучшей практикой и может привести к созданию хорошо построенных приложений. Автоматические тесты — отличный инструмент, позволяющий убедиться, что ваше приложение не сломается, когда вы вносите изменения или добавляете новые функции, и их нельзя игнорировать.
Существует несколько различных типов инструментов тестирования (или фреймворков), доступных для PHP, которые используют разные подходы — все они пытаются избежать ручного тестирования и необходимости в больших командах обеспечения качества, просто чтобы убедиться, что последние изменения не нарушили существующую функциональность.
Из Wikipedia:
Разработка через тестирование (TDD) — это процесс разработки программного обеспечения, основанный на повторении очень короткого цикла разработки: сначала разработчик пишет неудачный автоматизированный тестовый пример, который определяет желаемое улучшение или новую функцию, а затем создает код для прохождения этого теста. и, наконец, реорганизует новый код в соответствии с приемлемыми стандартами. Кент Бек, которому приписывают разработку или «повторное открытие» этой техники, заявил в 2003 году, что TDD поощряет простые конструкции и внушает доверие.
Существует несколько различных типов тестирования, которые вы можете выполнить для своего приложения::
Модульное тестирование — это подход к программированию, гарантирующий, что функции, классы и методы работают должным образом, с момента их создания на протяжении всего цикла разработки. Проверяя значения, входящие и исходящие из различных функций и методов, вы можете убедиться, что внутренняя логика работает правильно. Используя Dependency Injection и создавая “фиктивные” классы и заглушки, вы можете убедиться, что зависимости правильно используются для еще лучшего покрытия тестами.
Когда вы создаете класс или функцию, вы должны создать модульный тест для каждого поведения, которое они должны иметь.
На самом базовом уровне вы должны убедиться, что он ошибается, если вы отправляете ему неверные аргументы, и убедитесь,
что он работает, если вы отправляете ему действительные аргументы. Это поможет гарантировать, что при внесении изменений
в этот класс или функцию позже в цикле разработки старая функциональность продолжит работать должным образом. Единственной
альтернативой этому может быть var_dump()
в файле test.php, который нет возможности создать приложение - большое или
маленькое.
Еще одно применение модульных тестов — вклад в открытый исходный код. Если вы можете написать тест, который показывает неработающую функциональность (т. е. дает сбой), а затем исправить его и показать, что тест пройден, вероятность того, что патчи будут приняты, гораздо выше. Если вы запускаете проект, который принимает запросы на вытягивание, вы должны предложить это как требование.
PHPUnit — де-факто среда тестирования для написания модульных тестов для PHP-приложений, но есть несколько альтернатив:
Из Wikipedia:
Интеграционное тестирование (иногда называемое интеграцией и тестированием, сокращенно «I&T») — это этап тестирования программного обеспечения, на котором отдельные программные модули объединяются и тестируются как группа. Это происходит после модульного тестирования и перед проверочным тестированием. Интеграционное тестирование принимает в качестве входных данных модули, прошедшие модульное тестирование, группирует их в более крупные агрегаты, применяет тесты, определенные в плане интеграционного тестирования, к этим агрегатам и предоставляет на выходе интегрированную систему, готовую к системному тестированию.
Многие из тех же инструментов, которые можно использовать для модульного тестирования, можно использовать и для нтеграционного тестирования, поскольку используются многие из тех же принципов.
Иногда также известное как приемочное тестирование, функциональное тестирование состоит из использования инструментов для создания автоматических тестов, которые фактически используют ваше приложение, а не просто проверки того, что отдельные блоки кода ведут себя правильно и что отдельные блоки могут правильно общаться друг с другом. Эти инструменты обычно работают с реальными данными и имитируют реальных пользователей приложения.
Существует два разных типа разработки, ориентированной на поведение (BDD): SpecBDD и StoryBDD. SpecBDD фокусируется на техническом поведении кода, а StoryBDD фокусируется на бизнес-поведении или функциях или взаимодействиях. В PHP есть фреймворки для обоих типов BDD.
С помощью StoryBDD вы пишете удобочитаемые истории, описывающие поведение вашего приложения. Затем эти истории можно запускать как настоящие тесты для вашего приложения. Фреймворк, используемый в PHP-приложениях для StoryBDD, — это Behat, который вдохновлен проектом Ruby Cucumber и реализует Gherkin DSL для описания поведения функций.
С помощью SpecBDD вы пишете спецификации, описывающие, как должен вести себя ваш фактический код. Вместо тестирования функции или метода вы описываете, как должна вести себя эта функция или метод. PHP предлагает для этой цели фреймворк PHPSpec. Эта структура основана на проекте RSpec для Ruby.
Помимо отдельных фреймворков для тестирования и поведения, существует также ряд универсальных фреймворков и вспомогательных библиотек, полезных для любого предпочтительного подхода.
Приложения PHP можно развертывать и запускать на производственных веб-серверах несколькими способами.
PaaS предоставляет системную и сетевую архитектуру, необходимую для запуска приложений PHP в Интернете. Это практически не требует настройки для запуска PHP-приложений или PHP-фреймворков.
В последнее время PaaS стал популярным методом развертывания, размещения и масштабирования PHP-приложений любого размера. Вы можете найти список поставщиков PHP PaaS “Платформа как услуга” в нашем разделе ресурсов.
Если вы знакомы с системным администрированием или заинтересованы в его изучении, виртуальные или выделенные серверы дадут вам полный контроль над производственной средой вашего приложения.
PHP через встроенный в PHP диспетчер процессов FastCGI (FPM) очень хорошо сочетается с nginx, который представляет собой легкий высокопроизводительный веб-сервер. Он использует меньше памяти, чем Apache, и может лучше обрабатывать больше одновременных запросов. Это особенно важно для виртуальных серверов, у которых не так много свободной памяти.
PHP и Apache имеют долгую совместную историю. Apache легко настраивается и имеет множество доступных модулей для расширения функциональности. Это популярный выбор для общих серверов и простая настройка для PHP-фреймворков и приложений с открытым исходным кодом, таких как WordPress. К сожалению, по умолчанию Apache использует больше ресурсов, чем nginx, и не может обрабатывать столько посетителей одновременно.
Apache есть несколько возможных конфигураций для запуска PHP. Наиболее распространенным и простым в настройке является
prefork MPM с mod_php
. Хотя это не самое эффективное использование памяти, это самое простое в работе и использовании.
Это, вероятно, лучший выбор, если вы не хотите слишком углубляться в аспекты администрирования сервера. Обратите внимание,
что если вы используете mod_php, вы ДОЛЖНЫ использовать prefork MPM.
В качестве альтернативы, если вы хотите выжать из Apache больше производительности и стабильности, вы можете воспользоваться той же системой FPM, что и nginx, и запустить worker MPM или event MPM с mod_fastcgi или mod_fcgid. Эта конфигурация будет значительно более эффективной с точки зрения использования памяти и намного быстрее, но ее настройка потребует больше усилий.
Если вы используете Apache 2.4 или более позднюю версию, вы можете использовать mod_proxy_fcgi, чтобы получить отличную производительность, которую легко настроить.
Если вы обнаружите, что вручную вносите изменения в схему базы данных или запускаете тесты перед обновлением файлов (вручную), подумайте дважды! С каждой дополнительной ручной задачей, необходимой для развертывания новой версии вашего приложения, увеличивается вероятность потенциально фатальных ошибок. Независимо от того, имеете ли вы дело с простым обновлением, комплексным процессом сборки или даже стратегией непрерывной интеграции, автоматизация сборки — ваш друг.
Среди задач, которые вы, возможно, захотите автоматизировать, следующие:
Инструменты развертывания можно описать как набор сценариев, которые выполняют общие задачи развертывания программного обеспечения. Инструмент развертывания не является частью вашего программного обеспечения, он воздействует на ваше программное обеспечение ‘извне’.
Существует множество инструментов с открытым исходным кодом, которые помогут вам в автоматизации сборки и развертывании, некоторые из них написаны на PHP, а другие нет. Это не должно удерживать вас от их использования, если они лучше подходят для конкретной работы. Вот несколько примеров:
Phing может управлять процессом упаковки, развертывания или тестирования из XML-файла сборки. Phing (который основан на Apache Ant) предоставляет богатый набор задач, обычно необходимых для установки или обновления веб-приложения, и может быть дополнен дополнительными пользовательскими задачами, написанными на PHP. Это надежный и надежный инструмент, который существует уже давно, однако этот инструмент может показаться немного старомодным из-за того, как он работает с конфигурацией (XML-файлы).
Capistrano — это система для программистов среднего и продвинутого уровня, позволяющая выполнять команды структурированным, повторяемым образом на одной или нескольких удаленных машинах. Он предварительно настроен для развертывания приложений Ruby on Rails, однако с его помощью вы можете успешно развертывать системы PHP. Успешное использование Capistrano зависит от практических знаний Ruby и Rake.
Ansistrano — это пара ролей Ansible для простого управления процессом развертывания (развертывание и откат) для таких приложений, как PHP, Python и Ruby. Это порт Ansible для Capistrano. Он уже используется довольно многими PHP-компаниями.
Deployer — это инструмент развертывания, написанный на PHP. Это просто и функционально. Функции включают в себя параллельный запуск задач, атомарное развертывание и поддержание согласованности между серверами. Доступны рецепты общих задач для Symfony, Laravel, Zend Framework и Yii. Статья Юнеса Рафи Простое развертывание приложений PHP с помощью Deployer — отличное руководство по развертыванию вашего приложения с помощью этого инструмента.
Magallanes — еще один инструмент, написанный на PHP с простой настройкой в файлах YAML. Он поддерживает несколько cерверов и сред, атомарное развертывание и имеет несколько встроенных задач, которые вы можете использовать для общих инструментов и сред.
Управление серверами и их настройка могут оказаться непростой задачей при наличии большого количества серверов. Существуют инструменты для решения этой проблемы, поэтому вы можете автоматизировать свою инфраструктуру, чтобы убедиться, что у вас есть нужные серверы и что они правильно настроены. Они часто интегрируются с более крупными поставщиками облачного хостинга (Amazon Web Services, Heroku, DigitalOcean и т. д.) для управления экземплярами, что значительно упрощает масштабирование приложения.
Ansible — это инструмент, который управляет вашей инфраструктурой через файлы YAML. С ним легко начать работу, и он может управлять сложными и крупномасштабными приложениями. Существует API для управления облачными экземплярами, и он может управлять ими через динамическую инвентаризацию с использованием определенных инструментов.
Puppet — это инструмент со своим языком и типами файлов для управления серверами и конфигурациями. Его можно использовать в режиме мастер/клиент или в режиме «без мастера». В режиме «мастер/клиент» клиенты будут опрашивать центральные мастера на наличие новой конфигурации с заданными интервалами и при необходимости обновлять себя. В режиме без мастера вы можете вносить изменения в свои узлы.
Chef — это мощная платформа системной интеграции на основе Ruby, с помощью которой вы можете создать всю свою серверную среду или виртуальные блоки. Он хорошо интегрируется с Amazon Web Services через их сервис под названием OpsWorks.
Непрерывная интеграция — это практика разработки программного обеспечения, при которой члены команды часто интегрируют свою работу, обычно каждый человек интегрирует по крайней мере ежедневно, что приводит к множеству интеграций в день. Многие команды считают, что такой подход приводит к значительному сокращению проблем интеграции и позволяет команде быстрее разрабатывать целостное программное обеспечение. – Martin Fowler
Существуют разные способы реализации непрерывной интеграции для PHP. Travis CI проделал огромную работу, сделав непрерывную интеграцию реальностью даже для небольших проектов. Travis CI — это размещенная служба непрерывной интеграции. Может быть интегрировано с GitHub и предлагает первоклассную поддержку многих языков, включая PHP. GitHub имеет непрерывную интеграцию рабочих процессов с GitHub Actions.
Запуск вашего приложения в разных средах разработки и производства может привести к появлению странных ошибок при запуске. Также сложно поддерживать актуальность различных сред разработки с одной и той же версией для всех библиотек, используемых при работе с командой разработчиков.
Если вы разрабатываете для Windows и выполняете развертывание в Linux (или в любой другой системе, отличной от Windows) или разрабатываете в команде, вам следует рассмотреть возможность использования виртуальной машины. Это звучит сложно, но помимо широко известных сред виртуализации, таких как VMware или VirtualBox, существуют дополнительные инструменты, которые могут помочь вам настроить виртуальную среду за несколько простых шагов.
Vagrant помогает вам создавать виртуальные ящики поверх известных виртуальных сред и настраивает эти среды на основе одного файла конфигурации. Эти ящики можно настроить вручную, или вы можете использовать программное обеспечение для «подготовки», такое как Puppet или Chef, чтобы сделать это за вас. Подготовка базового блока — отличный способ убедиться, что несколько блоков настроены одинаково, и избавляет вас от необходимости поддерживать сложные списки команд «настройки». Вы также можете «уничтожить» свою базовую коробку и воссоздать ее без множества ручных операций, что упрощает создание «новой» установки.
Vagrant создает папки для совместного использования вашего кода между вашим хостом и вашей виртуальной машиной, что означает, что вы можете создавать и редактировать свои файлы на своем хост-компьютере, а затем запускать код внутри своей виртуальной машины.
Docker — облегченная альтернатива полноценной виртуальной машине — называется так потому, что все дело в «контейнерах». Контейнер — это строительный блок, который в простейшем случае выполняет одну конкретную работу, т.е. запуск веб-сервера. «Образ» — это пакет, который вы используете для сборки контейнера — у Docker есть полный репозиторий.
Типичное приложение LAMP может иметь три контейнера: веб-сервер, процесс PHP-FPM и MySQL. Как и в случае с общими папками в Vagrant, вы можете оставить файлы приложений там, где они есть, и указать Docker, где их найти.
Вы можете создавать контейнеры из командной строки (см. пример ниже) или, для простоты обслуживания, создать файл
docker-compose.yml
для своего проекта, указав, какие из них создавать и как они взаимодействуют друг с другом.
Docker может помочь, если вы разрабатываете несколько веб-сайтов и хотите разделить их, установив каждый на свою виртуальную машину, но у вас нет необходимого дискового пространства или времени, чтобы поддерживать все в актуальном состоянии. Это эффективно: установка и загрузка выполняются быстрее, вам нужно хранить только одну копию каждого образа, как бы часто он ни использовался, контейнерам требуется меньше оперативной памяти и они используют одно и то же ядро ОС, поэтому вы можете иметь больше серверов, работающих одновременно, и это занимает много времени. секунд, чтобы остановить и запустить их, не нужно ждать полной загрузки сервера.
После установки docker на вашем компьютере вы можете запустить веб-сервер с помощью одной команды.
Ниже будет загружена полнофункциональная установка Apache с последней версией PHP, сопоставление
/path/to/your/php/files
с корнем документа, который вы можете просмотреть по адресу http://localhost:8080
:
Это инициализирует и запустит ваш контейнер. -d
заставляет его работать в фоновом режиме. Чтобы остановить и запустить
его, просто запустите docker stop my-php-webserver
и docker start my-php-webserver
(остальные параметры снова не
нужны).
Приведенная выше команда показывает быстрый способ запуска базового сервера. Вы можете сделать гораздо больше (и тысячи готовых образов в Docker Hub). Потратьте время на изучение терминологии и прочтите Руководство пользователя Docker, чтобы извлечь из него максимальную пользу, и не запускайте случайно загруженный код, не проверив его безопасность — неофициальные образы могут не иметь последней версии патчей безопасности. Если вы сомневаетесь, придерживайтесь официальных репозиториев.
Сайт PHPDocker.io автоматически сгенерирует все файлы, необходимые для полнофункционального стека LAMP/LEMP, включая выбранную вами версию PHP и расширения.
PHP сам по себе довольно быстр, но узкие места могут возникнуть, когда вы устанавливаете удаленные соединения, загружаете файлы и т. д. К счастью, существуют различные инструменты для ускорения определенных частей вашего приложения или уменьшения количества раз выполнения этих различных трудоемких задач. нужно бежать.
Когда файл PHP выполняется, он должен быть сначала скомпилирован в opcodes (инструкции машинного языка для ЦП). Если исходный код не изменился, коды операций будут такими же, поэтому этот шаг компиляции становится пустой тратой ресурсов процессора.
Кэш opcode операций предотвращает избыточную компиляцию, сохраняя opcodes в памяти и повторно используя их при последовательных вызовах. Обычно он сначала проверяет подпись или время модификации файла, если были какие-либо изменения.
Вполне вероятно, что кеш opcode операции значительно улучшит скорость вашего приложения. Начиная с PHP 5.5 есть
встроенный — Zend OPcache. В зависимости от вашего пакета/дистрибутива PHP он обычно включен по умолчанию
— проверьте opcache.enable и вывод
phpinfo()
, чтобы убедиться. Для более ранних версий есть расширение PECL.
Подробнее о кэшах opcodes:
Бывают случаи, когда может быть полезно кэшировать отдельные объекты в вашем коде, например, с данными, получение которых дорого, или вызовами базы данных, результат которых вряд ли изменится. Вы можете использовать программное обеспечение для кэширования объектов, чтобы хранить эти фрагменты данных в памяти для чрезвычайно быстрого доступа в дальнейшем. Если вы сохраняете эти элементы в хранилище данных после их извлечения, а затем извлекаете их непосредственно из кэша для последующих запросов, вы можете добиться значительного повышения производительности, а также снизить нагрузку на серверы баз данных.
Многие из популярных решений для кэширования байт-кода также позволяют кэшировать пользовательские данные, так что есть еще больше причин воспользоваться ими. APCu и WinCache предоставляют API для сохранения данных из вашего PHP-кода в их кэш-память.
Наиболее часто используемыми системами кэширования объектов памяти являются APCu и memcached. APCu — отличный выбор для кэширования объектов, он включает в себя простой API для добавления ваших собственных данных в кэш памяти и очень прост в настройке и использовании. Единственное реальное ограничение APCu заключается в том, что он привязан к серверу, на котором установлен. С другой стороны, Memcached устанавливается как отдельная служба, и к ней можно получить доступ по сети, а это означает, что вы можете хранить объекты в сверхбыстром хранилище данных в центральном расположении, и множество различных систем могут извлекать из него данные.
Обратите внимание, что при запуске PHP как (Fast-) CGI-приложения внутри вашего веб-сервера каждый процесс PHP будет иметь свой собственный кеш, т. е. данные APCu не будут использоваться совместно вашими рабочими процессами. В этих случаях вы можете вместо этого рассмотреть возможность использования memcached, так как он не привязан к процессам PHP.
В сетевой конфигурации APCu обычно превосходит memcached по скорости доступа, но memcached сможет масштабироваться быстрее и дальше. Если вы не ожидаете, что ваше приложение будет запущено на нескольких серверах, или вам не нужны дополнительные функции, которые предлагает memcached, тогда APCu, вероятно, будет вашим лучшим выбором для кэширования объектов.
Пример логики с использованием APCu:
<?php
// check if there is data saved as 'expensive_data' in cache
$data = apcu_fetch('expensive_data');
if ($data === false) {
// data is not in cache; save result of expensive call for later use
apcu_add('expensive_data', $data = get_expensive_data());
}
print_r($data);
Обратите внимание, что до версии PHP 5.5 было расширение APC которое предоставляло как кеш объектов, так и кеш байт-кода. APCu — это проект по переносу кеша объектов APC на PHP 5.5+, поскольку PHP теперь имеет встроенный кеш байт-кода (OPcache).
PHPDoc — это неофициальный стандарт для комментирования PHP-кода. Доступно множество различных tags. Полный список тегов и примеров можно найти в PHPDoc manual.
Ниже приведен пример того, как вы можете задокументировать класс с помощью нескольких методов;
<?php
/**
* @author A Name <a.name@example.com>
* @link https://www.phpdoc.org/docs/latest/index.html
*/
class DateTimeHelper
{
/**
* @param mixed $anything Anything that we can convert to a \DateTime object
*
* @throws \InvalidArgumentException
*
* @return \DateTime
*/
public function dateTimeFromAnything($anything)
{
$type = gettype($anything);
switch ($type) {
// Some code that tries to return a \DateTime object
}
throw new \InvalidArgumentException(
"Failed Converting param of type '{$type}' to DateTime object"
);
}
/**
* @param mixed $date Anything that we can convert to a \DateTime object
*
* @return void
*/
public function printISO8601Date($date)
{
echo $this->dateTimeFromAnything($date)->format('c');
}
/**
* @param mixed $date Anything that we can convert to a \DateTime object
*/
public function printRFC2822Date($date)
{
echo $this->dateTimeFromAnything($date)->format('r');
}
}
Документация для класса в целом имеет тег @author и тег @link. Тег @author используется для документирования автора кода и может повторяться для документирования нескольких авторов. Тег @link используется для ссылки на веб-сайт, указывающий на связь между веб-сайтом и кодом.
Внутри класса у первого метода есть тег @param, документирующий тип, имя и описание параметра, передаваемого методу. Кроме того, он имеет теги @return и @throws для документирования типа возвращаемого значения и любых исключений, которые могут быть выброшены соответственно.
Второй и третий методы очень похожи и имеют один тег @param, как и первый метод. Важным отличием блока документации
второго и третьего методов является включение/исключение тега @return. @return void
явно сообщает нам, что возврата
нет; Исторически пропуск оператора @return void
также приводит к тому же действию (без возврата).
Трудно найти интересных и знающих членов сообщества PHP, когда вы только начинаете. Вы можете найти сокращенный список членов сообщества PHP, с которого можно начать:
Вместо того, чтобы изобретать велосипед, многие PHP-разработчики используют фреймворки для создания веб-приложений. Фреймворки абстрагируются от многих низкоуровневых проблем и предоставляют полезные, простые в использовании интерфейсы для выполнения общих задач.
Вам не нужно использовать фреймворк для каждого проекта. Иногда правильный путь — простой PHP, но если вам нужен фреймворк, то доступны три основных типа:
Микрофреймворки, по сути, представляют собой оболочку для максимально быстрой маршрутизации HTTP-запроса к обратному вызову, контроллеру, методу и т. д., и иногда они поставляются с несколькими дополнительными библиотеками для помощи в разработке, такими как базовые оболочки базы данных и тому подобное. Они широко используются для создания удаленных HTTP-сервисов.
Многие фреймворки добавляют значительное количество функций поверх того, что доступно в микрофреймворке; они называются платформами полного стека. Они часто поставляются в комплекте с ORM, пакетами аутентификации и т. д.
Компонентные фреймворки представляют собой наборы специализированных и одноцелевых библиотек. Разрозненные фреймворки на основе компонентов можно использовать вместе, чтобы создать микро- или фреймворк с полным стеком.
Как упоминалось выше, «Компоненты» — это еще один подход к общей цели создания, распространения и реализации общего кода. Существуют различные репозитории компонентов, два основных из которых:
С обоими этими репозиториями связаны инструменты командной строки, помогающие в процессах установки и обновления, и более подробно они описаны в разделе Dependency Management.
Существуют также фреймворки, основанные на компонентах, и поставщики компонентов, которые вообще не предлагают фреймворков. Эти проекты предоставляют еще один источник пакетов, которые в идеале практически не зависят от других пакетов или конкретных фреймворков.
Например, вы можете использовать FuelPHP Validation package, не используя саму структуру FuelPHP.
Illuminate components Laravel станут лучше отделены от фреймворка Laravel. На данный момент выше перечислены только те компоненты, которые лучше всего отделены от фреймворка Laravel.
Вы можете подписаться на еженедельные информационные бюллетени, чтобы быть в курсе новых библиотек, последних новостей, событий и общих объявлений, а также периодически публикуемых дополнительных ресурсов:
Есть также еженедельники на других платформах, которые могут вас заинтересовать; вот список некоторых.
Есть много книг по PHP; к сожалению, некоторые из них сейчас довольно старые и уже не точны. В частности, избегайте книг по “PHP 6”, версии, которой теперь никогда не будет. Следующим основным выпуском PHP после 5.6 был «PHP 7» частично из-за этого.
Этот раздел призван стать живым документом для рекомендуемых книг по разработке PHP в целом. Если вы хотите, чтобы ваша книга была добавлена, отправьте PR, и она будет рассмотрена на предмет актуальности.
Сообщество PHP столь же разнообразно, сколь и велико, и его члены готовы и желают поддерживать новых PHP-программистов. Подумайте о том, чтобы присоединиться к вашей локальной группе пользователей PHP (PUG) или посетить более крупные конференции PHP, чтобы узнать больше о передовых методах, показанных здесь. Вы можете общаться в IRC на канале #phpc на irc.freenode.com и следить за учетной записью @phpc в Twitter или Mastodon. Отправляйтесь туда, знакомьтесь с новыми разработчиками, изучайте новые темы и, прежде всего, заводите новых друзей! Другие ресурсы сообщества включают StackOverflow.
Если вы живете в большом городе, скорее всего, поблизости есть группа пользователей PHP. Вы можете легко найти местный
PUG на PHP.ug. Альтернативными источниками могут быть Meetup.com или поиск группа пользователей
php рядом со мной
с помощью вашей любимой поисковой системы (например, Google). Если вы живете в маленьком
городке, местного PUG может и не быть; если это так, начните один!
Особо следует отметить две глобальные группы пользователей: NomadPHP и PHPWomen. NomadPHP два раза в месяц предлагает групповые онлайн-встречи пользователей с презентациями ведущих спикеров PHP-сообщества. PHPWomen — это неэксклюзивная группа пользователей, изначально ориентированная на женщин в мире PHP. Членство открыто для всех, кто поддерживает более разнообразное сообщество. PHPWomen предоставляет сеть для поддержки, наставничества и обучения и в целом способствует созданию «дружественной к женщинам» и профессиональной атмосферы.
Сообщество PHP также организовывает крупнейшие региональные и национальные конференции в многих странах по всему миру. Хорошо известные участники PHP сообщества обычно выступают на этих крупнейших событиях, так что это большая возможность научиться прямо у лидеров индустрии.
ElePHPant замечательный талисман проекта PHP со слоном в его дизайне. Первоначально был спроектирован для проекта PHP в 1998 Vincent Pontier - духовный отец тысяч elePHPants по всему миру и 10-ю годами позже также родилась восхитительная игрушка плюшевого слонёнка. Сегодня elePHPants представляется на множестве PHP конференции с множеством PHP разработчиков и на их компьютерах для веселья и вдохновения.