PHP na Linha de Comando
O PHP ficou famoso por gerar páginas web, mas ele também é um programa comum de terminal. Com o comando php você roda arquivos, testa uma linha de código, recebe informações de quem chamou o programa e devolve um "deu certo" ou "deu errado" para o terminal. Nesta aula você vai usar o PHP como se usa qualquer comando do Linux.
- As três formas de rodar código:
php arquivo.php,php -rephp -a. - Como o programa recebe informações na hora de rodar:
$argve$argc. - Como perguntar algo e ler o que a pessoa digitou:
fgets(STDIN)ereadline. - Como terminar o programa com um código de saída (
exit) e conferir comecho $?. - Como transformar um arquivo PHP num comando, com
#!/usr/bin/env phpechmod +x.
Os exemplos rodam no terminal da Ana, numa pasta chamada cli. Se você ainda não instalou o PHP, veja Instalar no Linux; as missões rodam direto no editor do guia.
A ideia: o mesmo cozinheiro, duas portas
Imagine um restaurante. O cozinheiro (o PHP) pode receber pedidos pela janela do salão, onde os clientes são os navegadores e a resposta é uma página web. Mas ele também atende pela porta da cozinha, onde quem pede é você, digitando no terminal, e a resposta é texto na tela. A comida é a mesma; muda quem pede e como a resposta é entregue.
A porta da cozinha se chama CLI (command line interface, "interface de linha de comando"). É por ela que rodam os scripts de manutenção, as tarefas agendadas, o Composer, os testes, e também cada exemplo desta parte do guia. A janela do salão você conhece em O Servidor Embutido e em PHP Dentro do HTML.
1. php arquivo.php: rodar um arquivo
É o jeito que você já usou em Olá, Mundo: o comando php seguido do nome do arquivo.
<?php echo "Olá, mundo!\n";
$ php ola.php Olá, mundo!
- php
- O programa PHP, que fica numa pasta do sistema (aqui,
/opt/php/bin/php). - ola.php
- O arquivo a rodar. O PHP lê o arquivo, executa e mostra a saída no terminal. Quando o programa acaba, o prompt
$volta.
O arquivo pode estar em outra pasta: php projetos/ola.php ou php /home/ana/cli/ola.php. Se o nome estiver errado, o PHP avisa:
$ php olaa.php Could not open input file: olaa.php
Could not open input file = "não consegui abrir o arquivo de entrada". Confira o nome e a pasta onde você está (ls e pwd).
2. php -r: rodar uma linha, sem arquivo
Para testar uma coisa rápida, criar um arquivo dá trabalho. A opção -r (de run, "rodar") executa o código escrito ali mesmo, na linha de comando:
$ php -r 'echo 10 / 3, PHP_EOL;'
3.3333333333333
$ php -r 'echo strtoupper("ana"), "\n";'
ANA
$ php -r 'echo PHP_VERSION, "\n";'
8.5.8
- -r
- "Rode o código que vem a seguir."
- 'echo 10 / 3, PHP_EOL;'
- O código, entre aspas simples. Sem
<?php: no-r, tudo já é código PHP. OPHP_EOLé a quebra de linha (veja echo e print).
Duas armadilhas. A primeira: se você colocar <?php, o PHP reclama, porque no -r ele não espera essa marca:
$ php -r '<?php echo 1;' Parse error: syntax error, unexpected token "<", expecting end of file in Command line code on line 1
Repare no lugar do erro: em vez de um arquivo, Command line code ("código da linha de comando"). Para ler mensagens de erro, veja Lendo Erros do PHP.
A segunda armadilha é usar aspas duplas por fora. O terminal (o Bash) troca tudo que começa com $ pelo valor de uma variável dele, antes de o PHP ver o código. Como o Bash não tem variável $nome, ela vira nada:
$ php -r "$nome = 'Ana'; echo $nome;" Parse error: syntax error, unexpected token "=", expecting end of file in Command line code on line 1
O PHP recebeu = 'Ana'; echo ;, sem as variáveis. A regra: no php -r, aspas simples por fora, aspas duplas por dentro.
$ php -r '$nome = "Ana"; echo $nome;' Anaana@notebook:~/cli$ « sem quebra de linha, o prompt grudou na saída
Viu o Anaana@notebook? O echo não pulou linha, então o prompt do terminal apareceu colado no Ana. Não é erro: é só o próximo $ do terminal. Por isso os exemplos terminam com "\n" ou PHP_EOL.
3. php -a: o modo interativo
A opção -a (de interactive) abre uma "conversa" com o PHP: você digita uma instrução, aperta Enter, e ele executa na hora, sem arquivo. É ótimo para experimentar uma função.
$ php -a Interactive shell php > echo 10 / 3; 3.3333333333333 php > $nome = "Ana"; php > echo "Olá, $nome!"; Olá, Ana! php > echo strtoupper($nome); ANA php > exit
- Interactive shell
- "Modo interativo": o PHP avisa que entrou na conversa.
- php >
- O prompt do PHP (não do terminal): ele está esperando uma instrução. Escreva sem
<?php, terminando com;, como num arquivo, e aperte Enter. - $nome = "Ana";
- Criar uma variável não mostra nada, mas ela continua existindo nas linhas seguintes, até você sair.
- echo "Olá, $nome!";
- Repare que não foi preciso
\n: o modo interativo pula a linha sozinho antes do próximophp >. - exit
- Sai do modo interativo e volta ao terminal (Ctrl+D também funciona).
As setas funcionam como no terminal: ↑ traz de volta a instrução anterior, para você corrigir e repetir. Quem cuida disso é a extensão readline ("ler linha"), que vem junto com o PHP nas instalações comuns. O que você faz no php -a some quando você sai; para guardar, use um arquivo. Para experimentar código deste guia, o editor das missões também serve: você muda o código e clica em Rodar quantas vezes quiser.
| Você quer… | Use |
|---|---|
| Um programa de verdade, para guardar e rodar de novo | php arquivo.php |
| Uma conta ou uma função, uma vez só | php -r '…' |
| Experimentar várias linhas seguidas, vendo cada resultado | php -a ou o editor do guia |
4. $argv e $argc: o que veio depois do nome do arquivo
Comandos do Linux recebem informações na própria linha: em mkdir fotos, fotos é um argumento. Seus programas PHP também podem receber argumentos. Tudo o que você escreve depois do nome do arquivo chega ao programa em duas variáveis prontas:
<?php echo "Quantidade de itens: $argc\n"; echo "Item 0: $argv[0]\n"; echo "Item 1: $argv[1]\n"; echo "Item 2: $argv[2]\n";
$ php args.php Ana 29 Quantidade de itens: 3 Item 0: args.php Item 1: Ana Item 2: 29
- $argv
- argument values, "os valores dos argumentos". Um array, uma lista numerada a partir do zero. A posição
0é o nome do arquivo; os argumentos de verdade começam na1. - $argc
- argument count, "a contagem de argumentos": quantos itens o
$argvtem, contando o nome do arquivo. Por isso deu3para dois argumentos. - $argv[1]
- O item da posição 1:
Ana. Os colchetes escolhem a posição.
Quem separa os argumentos é o terminal, nos espaços. Para mandar um argumento com espaço dentro, use aspas. Para ver o array inteiro, o print_r ajuda (ele é explicado em var_dump e print_r):
<?php print_r($argv);
$ php ver-args.php "Ana Souza" 29 --cor=azul
Array
(
[0] => ver-args.php
[1] => Ana Souza
[2] => 29
[3] => --cor=azul
)
Repare: "Ana Souza" chegou como um argumento (as aspas sumiram, foram só para o terminal); o 29 chegou como texto, não como número; e --cor=azul chegou como está: o PHP não interpreta nada, quem decide o que cada argumento significa é o seu programa.
E se a pessoa não mandar o argumento?
<?php $nome = $argv[1]; echo "Olá, $nome!\n";
$ php saudacao.php Ana Olá, Ana! $ php saudacao.php Warning: Undefined array key 1 in /home/ana/cli/saudacao.php on line 2 Olá, !
Sem argumento, não existe a posição 1 no array, e o PHP avisa: "chave de array não definida: 1". O jeito curto de dar um valor padrão é o operador ?? ("se não existir, use isto"), que você vai estudar em ?? e ?->:
<?php $nome = $argv[1] ?? "visitante"; echo "Olá, $nome!\n";
$ php saudacao2.php Olá, visitante!
Missão: esta caixa roda o programa como php main.php Ana 29. Complete a segunda linha para usar o segundo argumento (a idade) e mostrar Olá, Ana! Você tem 29 anos.
<?php $nome = $argv[1]; $idade = "?"; echo "Olá, $nome! Você tem $idade anos.\n";
<?php $nome = $argv[1]; $idade = $argv[2]; echo "Olá, $nome! Você tem $idade anos.\n";
$argv só existe no terminal
Numa página web não há "linha de comando", então $argv não serve. Lá, as informações chegam pelo endereço e por formulários, em $_GET e $_POST (veja $_GET e $_POST).
5. STDIN: perguntar e ler o que a pessoa digitou
Argumentos são decididos antes de o programa rodar. Às vezes você quer perguntar durante: "Qual é o seu nome?", e esperar a resposta. O teclado chega ao programa por um canal chamado STDIN (standard input, "entrada padrão"). A função fgets lê uma linha dele:
<?php echo "Qual é o seu nome? "; $nome = trim(fgets(STDIN)); echo "Olá, $nome!\n";
$ php nome.php Qual é o seu nome? Ana « o programa para e espera; a Ana digitou Ana e Enter Olá, Ana!
- echo "Qual é o seu nome? ";
- A pergunta, sem
\n, para o cursor ficar na mesma linha. - STDIN
- Uma constante que o PHP cria sozinho no terminal: o canal de entrada (normalmente, o teclado).
- fgets(STDIN)
- file get string, "pegar um texto do arquivo": lê uma linha do canal, até o Enter. O programa fica parado esperando.
- trim(…)
- "Aparar": tira espaços e quebras de linha das pontas. Precisa dele porque o Enter que você apertou vem junto com o texto.
Veja o que acontece sem o trim. Aqui o echo Bruno | manda o texto Bruno (com o Enter) para a entrada do programa, como se alguém tivesse digitado:
$ echo Bruno | php nome-sem-trim.php Qual é o seu nome? Olá, Bruno ! « o Enter do "Bruno" veio junto e quebrou a frase $ echo Bruno | php nome.php Qual é o seu nome? Olá, Bruno!
(O Bruno não aparece depois da pergunta porque ninguém digitou: ele veio pelo cano |. Quando você digita, o terminal mostra as letras.)
A outra forma: readline
A função readline faz a pergunta e lê a resposta numa linha só, já sem o Enter no final:
<?php
$nome = readline("Qual é o seu nome? ");
echo "Olá, $nome!\n";
$ php nome-readline.php Qual é o seu nome? Ana « a Ana digitou Ana e Enter Olá, Ana!
Sem trim, e a exclamação ficou na mesma linha: o readline já devolve o texto sem o Enter. Como no php -a, a pessoa pode usar as setas para corrigir o que digitou antes de apertar Enter. Mas há um detalhe: quando a resposta não vem do teclado, e sim de um cano (|), a pergunta não aparece:
$ echo Bruno | php nome-readline.php Olá, Bruno!
| Forma | Vantagem | Cuidado |
|---|---|---|
trim(fgets(STDIN)) | Funciona em qualquer PHP de terminal | Precisa do trim e de um echo antes para a pergunta |
readline("pergunta") | Mais curta; permite usar as setas para corrigir o que digitou | A pergunta não aparece quando a entrada vem de um cano (|) |
Na dúvida, use trim(fgets(STDIN)). E lembre: o que chega do teclado é sempre texto, mesmo que a pessoa digite 29 (veja Conversão de Tipos).
Missão: esta caixa digita Bruno para o programa. Clique em Rodar: a exclamação caiu na linha de baixo. Conserte para sair Olá, Bruno! numa linha só, ainda lendo com fgets.
<?php echo "Qual é o seu nome? "; $nome = fgets(STDIN); echo "Olá, $nome!\n";
<?php echo "Qual é o seu nome? "; $nome = trim(fgets(STDIN)); echo "Olá, $nome!\n";
6. exit: terminar e dizer como foi
Todo programa de terminal, ao terminar, entrega um número para o sistema: o código de saída. 0 quer dizer "deu tudo certo"; qualquer outro número (de 1 a 255) quer dizer "algo deu errado", e cada programa escolhe o que cada número significa. O terminal guarda o código do último comando na variável $?:
$ php ola.php Olá, mundo! $ echo $? 0
Um programa PHP que chega ao fim normalmente sai com 0. Com um erro fatal, sai com 255 (veja Lendo Erros). E você pode escolher o código, e parar o programa onde quiser, com exit:
<?php echo "Conferindo o estoque...\n"; exit(3); echo "Esta linha nunca aparece\n";
$ php sair.php Conferindo o estoque... $ echo $? 3
- exit(3);
- "Termine o programa agora, com o código 3." O que vem depois não roda.
- echo $?
- Comando do terminal (não do PHP): mostra o código de saída do último comando. Tem que ser o comando logo depois, porque cada comando novo troca o valor.
Se você passar um texto em vez de um número, o exit mostra o texto e sai com 0:
<?php
exit("Arquivo de estoque não encontrado.\n");
$ php sair2.php Arquivo de estoque não encontrado. $ echo $? 0
Cuidado: a mensagem é de erro, mas o código diz "deu certo". Para avisar um problema de verdade, mostre a mensagem e depois use exit com um número diferente de zero. Você também vai ver die(…) em códigos por aí: é outro nome para o mesmo exit.
Para que serve o código de saída?
Para outros programas saberem se o seu deu certo. No terminal, && roda o segundo comando só se o primeiro saiu com 0:
$ php ola.php && echo "deu certo" Olá, mundo! deu certo $ php sair.php && echo "deu certo" Conferindo o estoque... « saiu com 3: o "deu certo" não rodou
É assim que scripts de instalação, tarefas agendadas e ferramentas de teste decidem se continuam ou param.
Mensagens de erro vão para STDERR
Assim como existe a entrada padrão, existem duas saídas: STDOUT (a normal, para onde vai o echo) e STDERR (a de erros). Mandar as mensagens de erro pela segunda permite separar o resultado dos avisos. Este programa exige um argumento:
<?php
$arquivo = $argv[1] ?? "";
if ($arquivo === "") {
fwrite(STDERR, "Uso: php estoque.php ARQUIVO\n");
exit(1);
}
echo "Lendo $arquivo...\n";
O if ("se") testa uma condição; você vai aprendê-lo em if, elseif, else. Aqui: se o nome do arquivo veio vazio, escreva o modo de usar em STDERR (fwrite = "escrever") e saia com 1.
$ php estoque.php Uso: php estoque.php ARQUIVO $ echo $? 1 $ php estoque.php 2>/dev/null « 2>/dev/null joga fora só a saída de erros $ php estoque.php produtos.csv Lendo produtos.csv... $ echo $? 0
7. Shebang: o arquivo PHP vira um comando
Até aqui você sempre escreveu php antes do arquivo. Com duas mudanças, o arquivo roda sozinho, como ls ou mkdir. A primeira é uma linha especial no topo, o shebang (o nome vem de #, "sharp", e !, "bang"):
#!/usr/bin/env php <?php echo "Oi! Eu sou um programa PHP.\n";
- #!
- Avisa o Linux: "para rodar este arquivo, use o programa que vem a seguir". Tem que ser os dois primeiros caracteres do arquivo, na linha 1.
- /usr/bin/env php
- "Procure o
phpnas pastas de programas e use-o." Assim o arquivo funciona onde quer que o PHP esteja instalado. - <?php
- Continua necessário, na linha 2.
O nome do arquivo não precisa terminar em .php: um comando chamado oi é mais agradável de digitar. A segunda mudança é dar permissão de execução ao arquivo:
$ ./oi bash: ./oi: Permissão negada $ ls -l oi -rw-rw-r-- 1 ana ana 63 out 16 20:50 oi $ chmod +x oi $ ls -l oi -rwxrwxr-x 1 ana ana 63 out 16 20:50 oi $ ./oi Oi! Eu sou um programa PHP.
- ./oi
- "Rode o arquivo
oidesta pasta" (./= a pasta atual). Na primeira vez, o Linux negou: o arquivo não tinha permissão de execução. - chmod +x oi
- "Mude a permissão (change mode): acrescente (
+) a execução (x)." Repare nosxque apareceram nols -l.
E a linha do shebang não aparece na saída: quando o PHP roda um arquivo que começa com #!, ele pula essa primeira linha. Por isso o mesmo arquivo também funciona do jeito de sempre:
$ php oi Oi! Eu sou um programa PHP.
O Windows não usa shebang nem chmod: lá você sempre roda com php arquivo.php. Todo o resto desta aula (-r, $argv, STDIN, exit) funciona igual. Veja Instalar no Windows e macOS.
Quando dá errado
$ php olaa.php Could not open input file: olaa.php
O que significa: "não consegui abrir o arquivo de entrada". O nome está errado ou você está em outra pasta.
Como consertar: ls mostra os arquivos da pasta atual; pwd mostra onde você está. Use a tecla Tab para completar o nome.
php -r com aspas duplas: "unexpected token "=""
$ php -r "$nome = 'Ana'; echo $nome;" Parse error: syntax error, unexpected token "=", expecting end of file in Command line code on line 1
O que significa: o terminal trocou $nome por nada antes de o PHP ver o código.
Como consertar: aspas simples por fora: php -r '$nome = "Ana"; echo $nome;'.
$argv
$ php saudacao.php Warning: Undefined array key 1 in /home/ana/cli/saudacao.php on line 2 Olá, !
O que significa: o programa esperava um argumento que não foi passado.
Como consertar: passe o argumento (php saudacao.php Ana) ou dê um valor padrão: $argv[1] ?? "visitante".
$ echo Bruno | php nome-sem-trim.php Qual é o seu nome? Olá, Bruno !
O que significa: o fgets devolve a linha com o Enter no final.
Como consertar: trim(fgets(STDIN)).
./arquivo
$ ./oi bash: ./oi: Permissão negada
O que significa: o arquivo não tem permissão de execução.
Como consertar: chmod +x oi. Confira também se o #!/usr/bin/env php está na primeira linha, sem espaço nem linha em branco antes.
Missão final: o programa da lojinha confere o estoque. Quando ele está zerado, deve mostrar Estoque vazio! e terminar com o código de saída 2, sem chegar à linha da venda. Complete a linha marcada.
<?php
$estoque = 0;
if ($estoque === 0) {
echo "Estoque vazio!\n";
// termine aqui, com o código 2
}
echo "Venda registrada.\n";
<?php
$estoque = 0;
if ($estoque === 0) {
echo "Estoque vazio!\n";
exit(2);
}
echo "Venda registrada.\n";
Referência
| Comando ou recurso | O que faz | Exemplo |
|---|---|---|
php arquivo.php | Roda um arquivo | php ola.php |
php -r '…' | Roda código direto (sem <?php; aspas simples por fora) | php -r 'echo 2 ** 10, "\n";' |
php -a | Modo interativo (prompt php >; sai com exit) | php -a |
php -l arquivo.php | Confere a sintaxe sem rodar (veja Erros) | php -l ola.php |
php -S localhost:8000 | Servidor web de teste (veja php -S) | |
php -v / php -m | Mostra a versão / as extensões instaladas | php -m |
$argv | Array: [0] = arquivo, [1] em diante = argumentos (sempre texto) | $argv[1] ?? "padrão" |
$argc | Quantos itens o $argv tem (inclui o arquivo) | php a.php x y → 3 |
trim(fgets(STDIN)) | Lê uma linha digitada, sem o Enter | $nome = trim(fgets(STDIN)); |
readline("…") | Pergunta e lê, já sem o Enter | $nome = readline("Nome: "); |
exit(N) / die(N) | Termina com o código N (0 = certo) | exit(1); |
exit("texto") | Mostra o texto e termina com código 0 | |
fwrite(STDERR, "…") | Escreve na saída de erros | |
echo $? | (Terminal) código de saída do último comando | |
#!/usr/bin/env php + chmod +x | Arquivo PHP executável como comando | ./oi |
Exercícios
1. Uma linha só
Complete para o PHP mostrar o resultado de 7 * 6 sem criar arquivo:
2. O segundo argumento
Em php nota.php Ana 9, complete para pegar o 9:
3. Executável
Complete o comando que dá permissão de execução ao arquivo relatorio:
4. Quanto vale $argc em php compras.php pão leite café?
5. Por que se usa trim em trim(fgets(STDIN))?
6. Um programa termina com exit(1);. O que o echo $? logo depois mostra, e o que isso quer dizer?
7. Qual destes comandos funciona como esperado?
Resumo
php arquivo.phproda um arquivo;php -r '…'roda uma linha (sem<?php, aspas simples por fora);php -aabre o modo interativo, com o promptphp >.$argvé a lista do que veio na linha de comando:[0]é o arquivo, os argumentos começam no[1], e tudo chega como texto.$argcconta os itens.- Para ler o teclado:
trim(fgets(STDIN)).readline("…")é mais curto e já tira o Enter. exit(N)termina o programa com o código N;0= certo, outro número = problema. No terminal,echo $?mostra o código.- Mensagens de erro vão para
STDERRcomfwrite(STDERR, "…"). #!/usr/bin/env phpna linha 1 +chmod +xtransformam o arquivo num comando:./oi.