PHP: полный мануал с примерами, функциями и ООП
Практический мануал PHP: от переменных и читаемого кода до безопасных форм, интеграций, базы данных и ООП на примере магазина. Учебный маршрут, поиск функций, подробные примеры, разбор ошибок и исходники для скачивания.

Дерево руководства
Глава 219 · С нуля → рабочая команда
PHP в командной строке: аргументы, потоки, ini и локальный сервер
Полная официальная ветка CLI: чем SAPI отличается от веба, все группы опций, запуск файлов, argv, стандартные потоки, interactive shell, php -S и CLI ini.
CLI превращает PHP-файл в команду, импортёр или worker
CLI запускает PHP без HTTP-запроса: из терминала, планировщика, CI или supervisor. Так делают импорт каталога, миграцию, очередь и диагностическую команду. Входом становятся аргументы и STDIN, результатом — STDOUT/STDERR и exit code. Браузер, cookie, $_GET и HTTP-заголовки сами не появляются.
- Вход:
php import.php --limit=2 products.csv - Действие: CLI передаёт argv, скрипт читает файл и печатает прогресс
- Результат: STDOUT для результата, STDERR для диагностики, exit 0/не 0 для планировщика
| Запуск | Когда нужен |
|---|---|
php script.php | Обычный файл; -f можно не писать. |
php -r "code" | Короткая одноразовая проверка без PHP-тегов; shell quoting зависит от оболочки. |
php -a | Интерактивная оболочка, если сборка поддерживает readline. |
php -S 127.0.0.1:8000 -t public | Локальный HTTP-стенд, не production. |
| scheduler/supervisor → php worker.php | Повторяемый процесс с явными timeout, restart и журналом. |
CLI и FPM — два способа запуска с разными входами и ini
SAPI — способ, которым окружение вызывает PHP. CLI не пишет HTTP-заголовки, показывает ошибки обычным текстом, не меняет текущий каталог на каталог файла и обычно имеет html_errors=0, implicit_flush=1, неограниченный max_execution_time, доступные $argc/$argv и отключённый обычный input-time. Проверяйте PHP_SAPI или php_sapi_name(), а не одно наличие $argv: register_argc_argv мог включить его в другом SAPI и с PHP 8.5 эта директива deprecated.
<?php
declare(strict_types=1);
echo 'SAPI: ', PHP_SAPI, "\n";
echo 'CLI: ', PHP_SAPI === 'cli' ? 'yes' : 'no', "\n";
echo 'HTTP headers: ', PHP_SAPI === 'cli' ? 'not emitted' : 'managed by SAPI', "\n";
echo 'argv available: ', isset($argv) ? 'yes' : 'no', "\n";
Ожидаемый результат
SAPI: cli
CLI: yes
HTTP headers: not emitted
argv available: yes
Проверка выполнится в CLI runtime. Веб-запуск покажет другой SAPI и не обязан иметь $argv.
| Различие | Следствие |
|---|---|
| Нет HTTP headers | header() не создаёт браузерный ответ; статус процесса задаёт exit. |
| Текущий каталог сохраняется | Относительный путь считается от cwd запуска. Для файлов рядом со скриптом используйте __DIR__. |
| Ошибки plain text | Логи удобны терминалу; HTML-разметка не вставляется. |
| max_execution_time обычно 0 | Долгий процесс всё равно получает собственный deadline, memory budget и supervisor. |
| CLI ini отдельный | Успех php -m не доказывает наличие расширения в FPM и наоборот. |
Опции PHP binary: диагностика, конфигурация и запуск
Список вашей сборки всегда доступен через php -h. Перед аргументом, начинающимся с дефиса, ставьте --, чтобы PHP перестал разбирать собственные опции. Команда -l проверяет синтаксис, но не выполняет код и не обнаружит вызов отсутствующей функции.
| Опция | Практическое действие |
|---|---|
| -a | Интерактивный режим. |
| -c path/file | Другой php.ini или каталог поиска. |
| -n | Не читать php.ini. |
| -d name=value | Переопределить ini только для процесса. |
| -f file / file | Выполнить файл. |
| -h, -? | Показать помощь. |
| -i | phpinfo в формате текущего SAPI. |
| -l | Только parse/lint; до PHP 8.3 — один файл за запуск. |
| -m | Список PHP и Zend modules. |
| -r code | Выполнить короткий код без <?php. |
| -B / -R / -F / -E | До строк / код на строку / файл на строку / после строк STDIN. |
| -H | Скрыть переданные аргументы от внешних инструментов, где поддерживается. |
| -S addr:port / -t docroot | Development server и его document root. |
| -s / -w | Подсвеченный исходник / исходник без комментариев и пробелов. |
| -v | Версия binary и Zend Engine. |
| --ini[=diff] | Загруженный ini и scan dirs; =diff появился в PHP 8.5. |
| --rf/--rc/--re/--rz/--ri | Reflection по function/class/extension/Zend extension/ini extension. |
# PowerShell
php -v
php --ini
php -m
php -l .\import.php
php --rf json_decode
php -d memory_limit=128M .\import.php -- --limit=50
# sh/bash: одинарные кавычки защищают $name от подстановки shell
php -r '$name="Анна"; echo $name, PHP_EOL;'
Команды относятся к оболочке, а не к синтаксису PHP, поэтому сохранены как contextual fragment. Версия и пути зависят от машины.
Файл, argv, getopt и разделитель --
В $argv[0] обычно находится имя скрипта, дальше — аргументы; $argc равно их количеству. Для простых именованных опций есть getopt(), для развитого интерфейса — библиотека console. Разбор ниже принимает фиксированный массив, чтобы точно показать договор; production передаст настоящий $argv.
<?php
declare(strict_types=1);
function parseImportArguments(array $argv): array
{
$script = array_shift($argv);
$limit = 100;
$file = null;
foreach ($argv as $argument) {
if (str_starts_with($argument, '--limit=')) {
$raw = substr($argument, 8);
if ($raw === '' || !ctype_digit($raw) || (int) $raw < 1) {
throw new InvalidArgumentException('limit должен быть целым > 0');
}
$limit = (int) $raw;
continue;
}
if ($file !== null) { throw new InvalidArgumentException('Лишний аргумент'); }
$file = $argument;
}
if ($file === null) { throw new InvalidArgumentException('Нужен CSV-файл'); }
return ['script' => $script, 'limit' => $limit, 'file' => $file];
}
$options = parseImportArguments(['import.php', '--limit=2', 'products.csv']);
echo 'Файл: ', $options['file'], "\n";
echo 'Лимит: ', $options['limit'], "\n";
Ожидаемый результат
Файл: products.csv
Лимит: 2
Каждый новый элемент синтаксиса имеет роль: array_shift забирает argv[0], foreach читает аргументы, continue переходит к следующему, throw прекращает запуск с понятной ошибкой.
Unix shebang #!/usr/bin/env php позволяет сделать файл исполняемым; строка должна быть первой, а путь env зависит от системы. Windows обычно запускает явный php.exe script.php. Не помещайте секреты в argv: их могут увидеть история shell и список процессов; читайте секрет из защищённого файла, vault или stdin по политике окружения.
STDIN, STDOUT, STDERR и EOF: данные вместо браузера
STDIN, STDOUT и STDERR — заранее открытые streams CLI. Данные можно передать pipeline, полезный результат отправить в STDOUT, предупреждения — в STDERR, а успех обозначить exit code 0. fgets(STDIN) читает строку и возвращает false при EOF; file_get_contents("php://stdin") читает весь остаток и подходит только при известном лимите.
<?php
declare(strict_types=1);
function streamLines($stream): Generator
{
while (($line = fgets($stream)) !== false) {
yield $line;
}
}
function summarizeLines(iterable $lines): array
{
$accepted = 0;
$rejected = 0;
foreach ($lines as $line) {
$line = trim($line);
if ($line === '') { continue; }
$columns = str_getcsv($line, ',', '"', '');
if (count($columns) !== 2 || !ctype_digit($columns[1])) {
$rejected++;
continue;
}
$accepted++;
}
return [$accepted, $rejected];
}
$input = fopen(__DIR__ . '/orders.csv', 'rb');
if ($input === false) { throw new RuntimeException('orders.csv не открыт'); }
[$accepted, $rejected] = summarizeLines(streamLines($input));
fclose($input);
echo "Принято: $accepted\nОтклонено: $rejected\n";
Ожидаемый результат
Принято: 2
Отклонено: 1
Выполненный опыт читает приложенный файл построчно: streamLines превращает resource в iterable Generator. В реальной команде summarizeLines(streamLines(STDIN)) обработает перенаправленные строки без загрузки всего файла в память.
# PowerShell
Get-Content .\orders.csv | php .\import.php
$ok = $LASTEXITCODE
# sh/bash
cat orders.csv | php import.php > accepted.txt 2> errors.log
status=$?
Pipeline и redirection принадлежат shell. Пример не исполняется verifier-ом PHP; он показывает, куда попадут stdout, stderr и exit code.
Интерактивная оболочка: исследовать, затем сохранить в файл
php -a запускает интерактивный режим. При наличии readline появляется полноценная interactive shell: prompt, история, tab completion, многострочные конструкции. Без readline сборка может показать только «Interactive mode enabled» и исполнять ввод построчно без тех же удобств. Проверьте php -m или extension_loaded("readline").
| Подходит | Не подходит |
|---|---|
| Быстро проверить выражение, формат даты, сигнатуру | Хранить важный код только в истории. |
Посмотреть var_dump небольшого значения | Вставлять production secrets в общую историю терминала. |
| Исследовать объект через reflection | Считать интерактивный опыт повторяемым тестом. |
Настройки cli.prompt и cli.pager относятся к readline shell. #cli.prompt=… и #cli.pager=… меняют их внутри сеанса; точный набор meta-команд зависит от текущей сборки. Проверяемый результат переносите в PHP-файл и тест.
php -S: быстрый локальный HTTP-стенд с router.php
Development server запускается php -S 127.0.0.1:8000 -t public router.php. Если router возвращает false, сервер отдаёт существующий статический файл; иначе router формирует ответ. Он не читает .htaccess и не заменяет nginx/Apache/FPM. Привязывайте лабораторию к loopback, не выставляйте её в интернет.
<?php
declare(strict_types=1);
$path = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH);
if ($path !== '/' && is_file(__DIR__ . '/public' . $path)) {
return false;
}
if ($path === '/health') {
header('Content-Type: application/json; charset=UTF-8');
echo json_encode(['status' => 'ok'], JSON_THROW_ON_ERROR);
return true;
}
http_response_code(404);
header('Content-Type: text/plain; charset=UTF-8');
echo 'Not Found';
return true;
Ожидаемый результат
GET /health → HTTP 200 и {"status":"ok"}; существующий /app.css отдаётся сервером; неизвестный путь → HTTP 404 и Not Found.
Синтаксис проверен. Реальный HTTP lifecycle проверяется отдельным loopback-стендом; здесь не делается ложное утверждение о веб-сервере production.
CLI ini: сначала определить SAPI и binary, потом править файл
CLI читает свой набор ini. Команды php --ini, php -i и php -r "echo php_ini_loaded_file();" отвечают только за этот binary/SAPI. FPM проверяется через защищённый диагностический endpoint или конфигурацию pool, а не через терминал.
| Директива CLI | Назначение |
|---|---|
cli_server.color | Цветной вывод встроенного development server. |
cli.prompt | Строка приглашения интерактивной readline shell. |
cli.pager | Команда pager для вывода interactive shell. |
-c | Выбрать файл/каталог ini для одного запуска. |
-n | Запустить без php.ini, полезно для изоляции конфигурации. |
-d name=value | Переопределить доступную директиву на время процесса. |
Не копируйте CLI ini поверх FPM вслепую: у web и worker разные лимиты, extensions и модель угроз. Вместо этого храните осознанный общий слой и отдельные SAPI overrides, а диагностику прикладывайте вместе с PHP_BINARY, PHP_SAPI, php --ini и php -m.
Код и руководство с собой
Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.
Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.
Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.


