PHP: путешествие от «Hello World» до фреймворков
PHP — это довольно популярный язык программирования. Много лет в интернете можно услышать утверждение, что PHP умирает. Однако язык до сих пор жив и активно используется. Если вы занимаетесь выбором языка для изучения в 2024 году, возможно, вам стоит обратить внимание на другие языки программирования, у языка появилось много достойных и более популярных конкурентов. Но если вы, всё-таки, решились и начали осваивать PHP, то этот материал для вас.
PHP преимущественно используется для разработки веб-приложений. Если быть точным, то серверной их части, которую обычно называют бэкендом. Это означает, что ваш код будет работать на сервере. Это несколько упрощает вам задачу, поскольку вам нужно заботиться только о том, чтобы ваше приложение работало только с определёнными версиями PHP, которые доступны на вашем сервере, а не адаптировать ваш код под множество версий браузера, чем вынуждены заниматься фронтенд разработчики.
Но даже не смотря на узкую специализацию языка, его всё-таки можно использовать и в других сферах, хоть и не так эффективно. Например, вполне можно писать приложения для десктопа или просто писать скрипты для командной строки.
PHP всегда привлекал к себе внимание начинающих за счёт низкого порога входа. Код на PHP прощает многие ошибки, которые не прощают другие языки. Вы можете часами разбираться почему ваше первое приложение не хочет запускаться, если будете писать на Java или Python. В PHP, обычно, проблем у начинающих возникает намного меньше. Это и достоинство и недостаток языка. Вы очень быстро сможете начать разрабатывать свои приложения, но позже, вы можете столкнуться с множеством ошибок в коде по мере роста вашего проекта и вам всё равно придётся углубиться в изучение основ, которые, в тех же Java и Python просто обязательны с первого дня.
Объектно ориентированный подход
Итак. Вы уже написали свой первый «Hello, World» на PHP и, возможно, даже пишите какие-то длинные скрипты, которые проводят некие магические вычисления. Чем больше данных, тем более запутанных становится ваш код. Вы постоянно вынуждены копировать куски одного и того же кода, чтобы выполнить одно и тоже действие в другом месте.
Постепенно приходит понимание что такое функция и вы начинаете переносить в них повторяющиеся куски кода. Теперь вместо
echo4*6+7;...echo12*3+20;...echo22*24+100;
в нашем коде появляется что-то вроде такого:
calc(4,6,7);...calc(12,3,20);...calc(22,24,100);...functioncalc($a,$b,$c) {echo$a*$b+$c;}
И пусть теперь вас ругают более опытные коллеги, что вы написали плохой код, но теперь вы, как минимум, не будете бегать по всему коду, искать вашу формулу и исправлять её, если заходим вместо этих операций с тремя значениями сделать что-то другое. А если у вас что-то сложнее простых арифметических действий, то вам теперь не нужно постоянно копировать этот самый кусок кода по всей программе, а просто вызвать вашу функцию.
Двигаемся дальше и видим, что ваш код обрастает огромными структурами, которые мы из раза в раз повторяете. Если нам нужно куда-то передать информацию о человеке, то мы используем массивы, например, так:
$user=array("name" => "Саша","birthday" => "2001-03-08","contacts" => array("phone" => "555-55-55","email" => "sasha@example.org" ));
Вроде бы всё понятно. Но эти структуры норовят вырасти в объёме. В них то и дело появляются новые поля и приходится снова и снова бегать по всему коду и искать, где есть подобные конструкции и редактировать их. Ещё и многоуровневые массивы, когда чтобы добраться до нужной информации нужно указать несколько квадратных скобок после имени массива чтобы добраться до нужных данных. Забыл один уровень и нужных данных у тебя нет. Ещё хуже, начинают вылезать всякие предупреждения. Жизнь потихоньку превращается в ад.
И тут вы узнаёте о чудодейственных классах, где вы не только можете хранить все наши ценные данные, не хуже чем в массивах, но ещё и перенести в них ваши функции, которые связаны с этими данными. Например, чтобы вычислить возраст, вы находите решение на каком-нибудь StackOverflow, делаете функцию getAge, и у вас получается что-то вроде такого:
$contacts=newContacts;$contacts->phone="555-55-55";$contacts->email="sasha@example.org";$user=newUser;$user->name="Саша";$user->birthday="2001-03-08";$user->contacts=$contacts;classUser{public$name;public$birthday=null;public$contacts;publicfunctiongetAge(){if ($this->birthday) {$birthday=new\DateTime($this->birthday);$interval=$birthday->diff(new\DateTime());return$interval->y;}returnfalse;}}classContacts{public$phone;public$email;}
Довольно многословно, но теперь наша IDE нам начинает подсказывать что и как называется. Уже не нужно держать в памяти всю структуру данных, достаточно просто воспользоваться подсказками. Если нам нужен телефон, то вы просто пишете
$phone=$user->contacts->phone;
Ваши старшие коллеги втирают нам что-то про инкапсуляцию, про чёрный ящик, сеттеры, геттеры... Но ваша задача решена и код работает.
Теперь вы знаете, что есть классы. Что в эти классах можно хранить свои переменные, которые называются свойствами и вкладывать функции, которые называются методами. Теперь вы, вместо вереницы параметров функции или метода, просто передаёте объект нужного класса, который содержит все необходимые данные.
Далее, возможно вы узнаёте про статические свойства и методы классов. Изучаете наследование…
Всемогущий composer
Вы успешно развиваете свои проекты, но начинаете понимать. Количество классов растёт с неимоверной скоростью. Вы уже сами путаетесь что и где подключать. Самое логичное, что вы могли придумать, класть один класс в отдельный файл. Но их стало настолько много, что от вереницы requireрябит в глазах. Нужно что-то с этим делать.
В интернете вы узнаёте про автозагрзку классов, про некий «composer». Наверно что-то сложное. Ищем как можно автоматически загружать классы. PHP всегда мог загрузить любой файл из указанных ему каталогов в include_path. Также есть описание, что можно написать свою функцию для автозагрузки. Немного исследуем вопрос и получаем следующий код, который размещаем в файле, который расположен в каталоге вместе с другими классами.
set_include_path(__DIR__);spl_autoload_extensions('.php');spl_autoload_register();
Здесь set_include_path задаёт путь, где будет производиться поиск файлов с классами, spl_autoload_extensionsзадаёт хвост для имени файла, который будет добавлен к имени класса, spl_autoload_register регистрирует автозагрузку классов. Увы, но данный код позволяет загружать классы только если в имени файлов все символы имени класса переведены в нижний регистр. Как это можно исправить? Написать свою функцию автозагрузки.
Тут вы узнаёте о пространствах имён (namespace) и ваш код автозагрузки классов из простого подключения класса превращается в какую-то уже довольно приличного размера функцию. И этот код придётся везде копировать.
Вы не первые, кто подумал об этом и уже довольно давно программисты PHP собрались и придумали себе инструмент — composer. Это скрипт, который написан на языке PHP. Всё, что вам нужно для его запуска, компонент php для запуска приложений из командной строки. Тем, кто пользуется Linux, повезло больше, потому что им достаточно установить соответствующий пакет в своей системе и, далее, пользоваться командой composer из командной строки. В Windows это сделать немного сложнее. Но даже если вы не хотите ничего ставить, вы просто можете скачать файл composer.phar и запускать его из командной строки Linux — ./composer.phar (не забывайте о флаге +x) или Windows — php.exe composer.phar, конечно, с указанием всех необходимых опций.
Чем же занимается этот скрипт? Он просто опрашивает одну или несколько баз данных на предмет наличия в них пакета с определённым именем. Основной базой данных является сайт https://packagist.org/. На этом сайте любой желающий может выкладывать свои пакеты. Естественно, в таком случае, все пакеты будут открыто доступны любому разработчику на PHP. Если вы хотите закрыть пакеты со своим кодом, то вам необходимо изучить документацию composer и создать свой собственный закрытый репозиторий с исходным кодом, который вы будете использовать. Создание проприетарного кода выходит за рамки данной статьи, поэтому будем считать, что скрывать вам нечего и вы используете только публично доступные репозитории. В этом случае, кроме установки composer на своё ПК, от нас никаких дополнительных настроек не требуется.
Чтобы добавить composer в свой проект достаточно выполнить команду composer init. Первый раз не нужно особо задумываться об ответах. Используйте значения по умолчанию и просто нажимайте Enter в ответ на все вопросы, пока скрипт не завершит свою работу. Все вводимые значения можно будет легко исправить даже просто правкой одного файла. В результате выполнения вашей команды в проекте появятся (если из ещё не было) две папки src/ и vendor/, а также файл composer.json, примерно следующего содержания:
{ "name": "fsa/composer", "autoload": { "psr-4": { "Fsa\\Composer\\": "src/" } }, "authors": [ { "name": "Sergei Fedotov", "email": "fsa@tavda.info" } ], "require": {}}
Этот файл имеет стандартный формат JSON. Как вы можете заметить, если самостоятельно запускали команду, в файле содержатся те самые значения, которые вы вводили или принимали по умолчанию на этапе инициализации. Содержимое этого файла может изменяться после выполнения команды composer. Кроме того, файл можно редактировать вручную. Но я не советую делать этого при знакомстве, потому что это может иметь побочные эффекты и вы можете просто нарушить структуру JSON файла. При достаточном опыте и понимании как работает composer, редактирование этого файла может стать вашим рутиным действием.
Рассмотрим самый явный вариант для начинающих. Вы ничего не хотите публиковать и вам composer нужен только для того, чтобы использовать уже готовые библиотеки кода для решения своих задач. В этом случае для вас очень мало интересного будет в файле composer.json.
- name — имя пакета. Используется только в случае публикации вашего пакета или приложения.
- autoload — настройка автозагрузки классов. Стоит обратить на это внимание!
- authors — информация об авторах. Может быть полезно только в случае публикации вашего пакета или приложения.
- require — это список сторонних пакетов, которые будут вам требоваться.
Кроме require в файле может присутствовать параметр require-dev. По сути это единый список используемых сторонних пакетов. Однако некоторые пакеты могут быть вам нужны только на этапе разработки вашего проекта. Вот именно эти пакеты и будут располагаться в секции require-dev. Когда наступит время развернуть приложение на сервере, вы можете просто сказать composerиспользовать пакеты только из секции require.
Папка src/ в корне проекта. Это ни что иное, как папка для хранения ваших классов, которые необходимо будет загружать. Аналогичная папка есть практически во всех пакетах, которые предоставляет composer. Именно она указана в секции autoload и в любой момент может быть названа другим именем или перемещена совершенно в другое место на диске. Если вы её удалите, то ничего страшного не произойдёт. Просто composer больше не сможет автоматически загрузить оттуда классы, которые вам необходимы. Если папка была создана автоматически, то она пустая.
Папка vendor/ в корне проекта. Это основной каталог, где composer хранит всё необходимое для своей работы. И, пожалуй, единственным файлом, на который требуется обратить внимание на этапе знакомства с composer — файл vendor/autoload.php. Именно его необходимо будет подключить внутри своего файла PHP, чтобы у вас начала работать автозагрузка классов. Эту папку почти всегда можно безболезненно удалить с вашего диска и создать заново, но для этого потребуется доступ в интернет (или каким-то чудом необходимые данные окажутся в кэше на вашем ПК). Никаких изменений внутри этой папки категорически не рекомендуется делать, потому что они могут быть легко утеряны. Небольшой спойлер. Путём настройки composer можно оптимизировать процесс поиска классов и сделать его быстрее. Это можно делать на боевых серверах, чтобы ускорить обработку запросов. При разработке лучше пользоваться тем файлом, что вам предоставлен по умолчанию, потому что в этом случае у вас не будет неожиданных побочных эффектов после редактирования ваших классов.