Команды PHP CLI: полное руководство по настройке окружения
Командная строка PHP (CLI) предоставляет широкие возможности для выполнения скриптов, автоматизации задач, тестирования и отладки без участия веб-сервера. В этой части статьи рассматриваются основные способы взаимодействия с PHP из терминала, включая запуск файлов, передачу параметров, работу с потоками ввода-вывода и использование встроенного сервера.
Основные возможности командной строки PHP
Как выполнить PHP-скрипт из командной строки?
Самый распространённый способ запуска PHP-скрипта – указать интерпретатор php и путь к файлу. Если PHP установлен и добавлен в переменную окружения PATH, команда php script.php запустит файл script.php в текущей директории. PHP выполнит код и выведет результат в консоль.
php script.phpPhp не является внутренней или внешней командой (php не является внутренней или внешней командой)
В скрипте можно использовать константы PHP_SAPI (значение 'cli') или функцию php_sapi_name(), чтобы убедиться, что выполнение происходит в режиме командной строки.
Типичная ошибка: Could not open input file: script.php. Это сообщение появляется, если файл не найден. Необходимо проверить путь и наличие файла. Также может возникнуть синтаксическая ошибка – PHP Parse error. Перед запуском рекомендуется проверять синтаксис командой php -l script.php.
Как передать аргументы в PHP-скрипт при запуске?
Аргументы командной строки помещаются после имени файла. Внутри скрипта они доступны через суперглобальный массив $argv (первый элемент – имя скрипта) и переменную $argc (количество аргументов).
php script.php arg1 arg2 arg3Php could not find driver (ошибка "could not find driver" в php)
Пример скрипта, выводящего переданные аргументы:
<?php
foreach ($argv as $index => $arg) {
echo "Arg $index: $arg\n";
}
?>
Get env php (получение переменных окружения)
Arg 0: script.php Arg 1: arg1 Arg 2: arg2 Arg 3: arg3
Usr share php (путь usr/share/php)
Возможные проблемы: если аргумент содержит пробелы, его следует заключать в кавычки, иначе оболочка разделит его на несколько аргументов. Например: php script.php "слово с пробелами". Также некоторые специальные символы (например, $) могут интерпретироваться оболочкой – их нужно экранировать.
Как выполнить произвольный PHP-код без создания файла?
Опция -r позволяет передать код прямо в командной строке. Это удобно для быстрых проверок или однострочников.
php -r "echo 'Hello, World!';"Php command line (командная строка php (cli))
Hello, World!
Можно использовать сложные конструкции, но важно корректно экранировать кавычки. Рекомендуется снаружи ставить одинарные кавычки, а внутри – двойные.
Распространённая ошибка: при использовании двойных кавычек снаружи оболочка может интерпретировать переменные. Например, php -r "echo $foo;" вызовет ошибку, если переменная оболочки не определена. Правильно: php -r 'echo "$foo";' или экранирование.
Как использовать интерактивный режим (REPL) PHP?
Режим -a (interactive) запускает оболочку PHP, где можно вводить код построчно. Каждое выражение тут же выполняется и выводит результат (если есть).
php -a
Interactive shell
php > echo 'test';
test
php > exit
В интерактивном режиме доступны автодополнение (Tab) и история команд. Это полезно для экспериментов и отладки отдельных выражений.
Ограничение: некоторые функции, требующие полной инициализации модулей, могут работать некорректно. Например, функции сессии могут выдавать предупреждения. Для выхода используется команда exit или quit.
Как запустить встроенный веб-сервер PHP?
Опция -S позволяет поднять легковесный веб-сервер, полезный для тестирования приложений без Apache или Nginx.
php -S localhost:8000
Сервер запускается в текущей директории, обслуживая статические файлы и PHP-скрипты. Можно указать корневой каталог и маршрутизатор (роутинг) через третий параметр.
php -S localhost:8000 -t /path/to/public
php -S localhost:8000 router.php
Предупреждение: встроенный сервер однопоточный и не предназначен для production. При каждом запросе он выполняет код последовательно, что может приводить к блокировкам. Также не поддерживается HTTPS.
Как проверить синтаксис PHP-файла?
Опция -l (lint) анализирует файл на наличие синтаксических ошибок без выполнения.
php -l script.php
No syntax errors detected in script.php
Если ошибка есть, будет указан номер строки и описание. Этот метод полезен в CI/CD или перед деплоем.
Примечание: проверка не выявляет логические ошибки или проблемы с производительностью. Для полного анализа используются статические анализаторы.
Как получить информацию о PHP и установленных модулях?
Команда php -i выводит расширенную конфигурацию, аналогичную функции phpinfo() в веб-версии. php -m показывает список загруженных модулей. php -v отображает версию.
php -i | grep memory_limit
php -m
php -v
memory_limit => 128M => 128M [PHP Modules] calendar, Core, ctype, ... PHP 8.3.6 (cli) (built: Apr 11 2024 17:44:48) ( NTS )
Ошибка: если команда не найдена, значит PHP не установлен или не добавлен в PATH. Необходимо указать полный путь к исполняемому файлу.
Как использовать альтернативный php.ini для CLI?
Опция -c позволяет указать путь к конфигурационному файлу. Это удобно, когда нужно выполнить скрипт с особыми настройками, отличными от основного php.ini.
php -c /path/to/custom.ini script.php
Можно также временно изменить отдельные директивы с помощью -d.
php -d memory_limit=256M -d max_execution_time=60 script.php
Проблема: не все директивы допускают изменение во время выполнения через -d. Например, extension может быть только из ini-файла. Если указанный файл отсутствует, PHP использует стандартный.
Как читать данные из STDIN в PHP-скрипте?
PHP поддерживает поток php://stdin, который можно читать, например, с помощью file_get_contents() или fgets(). Это позволяет обрабатывать данные, переданные через конвейер (pipe).
php -r "echo strtoupper(file_get_contents('php://stdin'));"
Вызов в командной строке:
echo 'hello' | php -r "echo strtoupper(file_get_contents('php://stdin'));"
HELLO
Ошибка: если не перенаправлять STDIN, скрипт будет ожидать ввод с клавиатуры. Для завершения ввода используется Ctrl+D (Unix) или Ctrl+Z (Windows).
Как направлять ошибки в STDERR?
В CLI-режиме можно явно писать в поток STDERR с помощью fwrite(STDERR, 'сообщение'). Это позволяет отделить обычный вывод от сообщений об ошибках.
php -r 'fwrite(STDERR, "Ошибка\n"); echo "Нормальный вывод\n";'
В оболочке можно перенаправить STDERR в файл:
php script.php 2>error.log
Проблема: если забыть перенаправить STDERR, ошибки будут выводиться на экран вместе с обычным выводом, что может затруднить автоматическую обработку.
Как обрабатывать длинные и короткие опции командной строки (getopt)?
Функция getopt() разбирает аргументы, переданные скрипту, в соответствии с заданными опциями. Она поддерживает как короткие (-v), так и длинные (--verbose) опции.
<?php
$options = getopt('v::', ['verbose::']);
if (isset($options['v']) || isset($options['verbose'])) {
echo 'Режим подробного вывода включён';
}
?>
Запуск: php script.php -v или php script.php --verbose.
Ошибка: если в опциях указаны несуществующие значения, getopt может вернуть некорректный результат. Следует запускать скрипт с опцией -- для отделения опций от аргументов.
Расширенные примеры использования PHP CLI
Демон с обработкой сигналов
Скрипт может работать как долгоиграющий процесс, реагируя на сигналы от операционной системы. Для этого используются функции pcntl_signal() и pcntl_signal_dispatch().
<?php
declare(ticks = 1); // для старых версий PHP, в PHP 8 не требуется
pcntl_signal(SIGTERM, function ($signo) {
echo "Получен сигнал $signo, завершаю работу.\n";
exit(0);
});
pcntl_signal(SIGINT, function () {
echo "Прерывание (Ctrl+C). Выход.\n";
exit(0);
});
echo "Демон запущен. PID: " . getmypid() . "\n";
while (true) {
echo "Работаю...\n";
sleep(2);
pcntl_signal_dispatch();
}
?>
Результат (при запуске и отправке SIGTERM):
Демон запущен. PID: 12345 Работаю... Работаю... Получен сигнал 15, завершаю работу.
Параллельное выполнение с помощью pcntl_fork
В CLI-режиме возможно создавать дочерние процессы для параллельной обработки. Функция pcntl_fork() возвращает 0 в дочернем процессе и PID потомка в родительском.
<?php
$pids = [];
for ($i = 1; $i <= 3; $i++) {
$pid = pcntl_fork();
if ($pid == -1) {
die("Не удалось создать процесс");
} elseif ($pid == 0) {
// Дочерний процесс
echo "Дочерний процесс $i начал работу (PID: " . getmypid() . ")\n";
sleep(2);
echo "Дочерний процесс $i завершён.\n";
exit(0);
} else {
$pids[] = $pid;
}
}
// Родитель ждёт завершения всех потомков
foreach ($pids as $pid) {
pcntl_waitpid($pid, $status);
echo "Родитель: процесс $pid завершён с кодом " . pcntl_wexitstatus($status) . "\n";
}
?>
Пример вывода:
Дочерний процесс 1 начал работу (PID: 12346) Дочерний процесс 2 начал работу (PID: 12347) Дочерний процесс 3 начал работу (PID: 12348) Дочерний процесс 1 завершён. Родитель: процесс 12346 завершён с кодом 0 Дочерний процесс 2 завершён. Родитель: процесс 12347 завершён с кодом 0 Дочерний процесс 3 завершён. Родитель: процесс 12348 завершён с кодом 0
Взаимодействие с внешними программами через proc_open
Функция proc_open() позволяет запустить внешнюю команду и управлять её потоками ввода-вывода. Это мощный инструмент для автоматизации.
<?php
$descriptorspec = [
0 => ['pipe', 'r'], // stdin
1 => ['pipe', 'w'], // stdout
2 => ['pipe', 'w'], // stderr
];
$process = proc_open('cat', $descriptorspec, $pipes);
if (is_resource($process)) {
fwrite($pipes[0], 'Привет, proc_open!');
fclose($pipes[0]);
$stdout = stream_get_contents($pipes[1]);
fclose($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
$return = proc_close($process);
echo "STDOUT: $stdout\n";
echo "STDERR: $stderr\n";
echo "Код возврата: $return\n";
}
?>
Результат:
STDOUT: Привет, proc_open! STDERR: Код возврата: 0
Интерактивный ввод с историей через readline
Расширение readline предоставляет функции для построчного ввода с автодополнением и историей команд. Это удобно для создания собственных REPL-интерфейсов.
<?php
$history = [];
while (true) {
$line = readline('php> ');
if ($line === false || trim($line) === 'exit' || trim($line) === 'quit') {
break;
}
readline_add_history($line);
try {
$result = eval($line);
if ($result !== null) {
var_dump($result);
}
} catch (Throwable $e) {
echo "Ошибка: " . $e->getMessage() . "\n";
}
}
?>
Запуск и ввод нескольких выражений:
php> 2 + 2
int(4)
php> strtoupper('hello')
string(5) "HELLO"
php> exit
Цветной вывод в консоли
С помощью ANSI-escape последовательностей можно добавлять цвета и стили к выводу в терминале.
<?php
function colorize($text, $color = 'white', $background = null, $bold = false) {
$colors = [
'red' => 31, 'green' => 32, 'yellow' => 33, 'blue' => 34,
'magenta' => 35, 'cyan' => 36, 'white' => 37,
];
$bg = null;
if ($background && isset($colors[$background])) {
$bg = $colors[$background] + 10; // фон = 40-47
}
$code = '';
if ($bold) $code .= "\033[1;";
else $code .= "\033[0;";
$code .= $colors[$color];
if ($bg) $code .= ";" . $bg;
$code .= "m";
return $code . $text . "\033[0m";
}
echo colorize('Красный текст', 'red') . "\n";
echo colorize('Зелёный жирный', 'green', null, true) . "\n";
echo colorize('Белый на синем фоне', 'white', 'blue') . "\n";
?>
Результат будет разноцветным в поддерживающем терминале.