SlideShare uma empresa Scribd logo
1 de 35
Baixar para ler offline
Roteiro
Scripts CLI
Lidando com argumentos, streams e roteamento de comandos1.
Robôs
Gerenciando início e término de robôs, usando pcntl ou pthreads2.
Reutilização
Criando códigos que rodem em mais de um ambiente3.
É a melhor solução para o meu problema?
Primeiro, considere se você está usando as melhores ferramentas para cada tipo de trabalho
Scripts CLI
Criando utilitários para a linha de comando
Argumentos
As variáveis $argc e $argv guardam
informações sobre os argumentos do script
$argv é um array com os argumentos passados, sendo
que o índice 0 contém o nome do script invocado
if ($argc == 1) {
echo "Uso: php {$argv[0]} <comando>" . PHP_EOL;
exit(2);
}
switch ($argv[1]) {
case 'run':
// ...
break;
default:
// ...
break;
}
getopt()
array getopt( string $options [, array $longopts [, int &$optind ]] )
As opções podem ser:
Caracteres individuais: não aceitam valores
Caracteres seguidos por um dois-pontos: valor obrigatório
Caracteres seguidos por dois dois-pontos: valor opcional
$options = getopt(
'ab:c::',
['verbose', 'user:', 'password::']
);
// php getopt.php -a -b valor -c1 --verbose 
// --user root --password
array(6) {
["a"] => bool(false)
["b"] => string(5) "valor"
["c"] => string(1) "1"
["verbose"] => bool(false)
["user"] => string(4) "root"
["password"] => bool(false)
}
I/O Streams
Uso das funções fopen , fgets , fputs ,
stream_get_line e diversas outras
Disponibilização das constantes STDIN , STDOUT e
STDERR
// Leitura do STDIN
echo "Qual seu nome? ";
$line = trim(fgets(STDIN));
echo "Bem-vindo, {$line}." . PHP_EOL;
// Saída para STDERR
fputs(STDERR, 'Erro no sistema');
Streams
Uso de funções como stream_context_create , stream_copy_to_stream ,
stream_filter_append , entre outras
Referências
Manual do PHP: php.net/stream
Palestra do Alexandre Gaigalas na PHP Experience em 2016
// Exemplo simples do poder das streams
stream_filter_append(STDERR, 'string.toupper');
stream_copy_to_stream(STDIN, STDERR);
Roteamento de comandos
Organize seu script para que ele seja
modular
Crie estrutura de controllers para facilitar a manutenção
if ($argc != 3) {
echo "Uso: {$argv[0]} " . PHP_EOL;
exit(2);
}
include 'vendor/autoload.php';
array_shift($argv); // nome do script
$module = array_shift($argv); // ou $options['module
$class = "MyCliControllers{$module}";
if (!class_exists($class)) {
throw new DomainException("Módulo {$module} não
}
$command = array_shift($argv); // ou $options['comma
if (!method_exists($class, $command)) {
throw new DomainException("Comando {$command} nã
}
(new $class())->{$command}($argv); // ou $options
Bibliotecas
ZendConsole
Retirado da documentação o cial
// config/autoload/*.php
return [
'console' => [
'router' => [
'routes' => [
'user-reset-password' => [
'options' => [
'route' => 'user resetpassword [--verbose|-v] <em
'defaults' => [
'controller' => ApplicationControllerIndexCont
'action' => 'resetpassword'
]
]
]
]
]
]
];
Bibliotecas
ZendConsole
use ZendMvcControllerAbstractActionController;
class IndexController extends AbstractActionController
{
public function resetpasswordAction()
{
$request = $this->getRequest();
if (! $request instanceof ZendConsoleRequest) {
throw new RuntimeException('Requisição inválida');
}
$email = $request->getParam('email');
/* ... */
if ($request->getParam('verbose') || $request->getParam('v')) {
/* ... */
}
return 'Senha enviada com sucesso';
}
}
Adaptado da documentação o cial
Bibliotecas
Symfony Console
// application.php
require __DIR__.'/vendor/autoload.php';
$application = new SymfonyComponentConsoleApplication();
$application->add(new AppCommandCreateUserCommand());
$application->run();
Adaptado da documentação o cial
Bibliotecas
Symfony Console
Adaptado da documentação o cial
// src/Command/CreateUserCommand.php
namespace AppCommand;
use SymfonyComponentConsoleCommandCommand;
use SymfonyComponentConsoleInputInputInterface;
use SymfonyComponentConsoleOutputOutputInterface;
class CreateUserCommand extends Command
{
protected function configure()
{
/* ... */
}
protected function execute(InputInterface $input, OutputInterface $outpu
{
/* ... */
}
}
Bibliotecas
Symfony Console
protected function configure()
{
$this
// Nome do comando, executado pelo bin/console
->setName('app:create-user')
// Descrição do comando ao executar bin/console list
->setDescription('Cria um novo usuário.')
// Descrição completa ao invocar o --help
->setHelp('Esse comando permite você criar um novo usuário...')
// Argumento obrigatório
->addArgument(
'username',
SymfonyComponentConsoleInputInputArgument::REQUIRED,
'Nome de usuário'
);
}
Adaptado da documentação o cial
Bibliotecas
Symfony Console
Adaptado da documentação o cial
protected function execute(InputInterface $input, OutputInterface $output)
{
// Imprime várias linhas (automaticamente adicionando n)
$output->writeln([
'Criando usuário',
'===============',
'',
]);
// Imprime sem n
$output->write('Nome de usuário: ');
$output->write($input->getArgument('username'));
}
Bibliotecas
Outras opções
Laravel Zero CLImate
Aura.Cli CLIFramework
Robôs
Usando o PHP para criar daemons
Gerenciador de robôs
Para iniciar, terminar e acompanhar a
execução
Ou você pode ter daemons "auto-executáveis" - por
exemplo, diretamente via cron
interface DaemonManagerInterface
{
// Inicia todos os daemons
public function start();
// Inicia um daemon específico
public function startDaemon($class);
// Para todos os daemons
public function stop();
// Para um daemon específico
public function stopDaemon($class);
// Lista os daemons que devem ser iniciados
protected function getActive();
// Monitora o status de cada daemon
protected function watchStatus();
}
pcntl
Extensão Process Control
Manual do PHP: php.net/pcntl
pcntl_fork(); // Faz um fork do processo atual
pcntl_signal_dispatch(); // Invoca os handlers para
pcntl_signal(); // Instala um handler
pcntl_sigprocmask(); // Bloqueia/desbloqueia sinais
pcntl_sigtimedwait(); // Espera por um sinal, com ti
pcntl_sigwaitinfo(); // Espera por um sinal
pcntl_wait(); // Aguarda/retorna o status de um filh
pcntl_waitpid(); // Aguarda/retorna o status de um f
Fluxo simples de execução
Utilizando pcntl_fork()
Fazendo fork do processo atual
public function startDaemon($class)
{
$pid = pcntl_fork();
if ($pid == -1) {
throw new RuntimeException("Houve um erro no
}
if ($pid) {
// Processo pai
return $pid;
}
// Processo filho (robô)
$daemon = new $class();
$daemon->run();
die();
}
Fluxo simples de execução
Utilizando pcntl_waitpid()
int pcntl_waitpid(
int $pid ,
int &$status
[, int $options = 0
[, array &$rusage ]]
)
protected function watchStatus() {
$count = count($this->pool);
while ($count > 0) {
foreach ($this->pool as $index => $pid) {
// Retorna o PID do filho se ele estiver
if (pcntl_waitpid($pid, $status, WNOHANG
unset($this->pool[$index]);
echo "Filho {$index} morreu..." . PH
--$count;
}
}
sleep(1);
}
}
Fluxo simples de execução
Utilizando sinais
Para lidar com eventos externos
pcntl_signal(SIGINT, [$this, 'signalHandler']);
// Para SIGTERM, SIGINT, SIGHUP, SIGUSR1, etc
public function signalHandler($signal) {
switch ($signal) {
case SIGTERM:
case SIGINT:
case SIGHUP:
echo 'Terminando graciosamente...';
die();
case SIGUSR1:
echo "Capturado sinal SIGUSR1 " . PHP_EO
break;
/* ... */
}
}
Demonstração
pthreads
Biblioteca que implementa o padrão POSIX
Threads
A V3 foi totalmente reescrita para uso no PHP 7.2
Necessita do PHP compilado com ZTS (Zend Thread
Safety)
Classes disponíveis
Threaded Thread
Worker Collectable
Modifiers Pool
Mutex Cond
Volatile
Classe Thread
Ela deve implementar o método run()
class Task extends Thread
{
private $threadId;
public function __construct($threadId)
{
$this->threadId = (int) $threadId;
}
public function run()
{
echo "Iniciando a thread {$this->threadId}"
sleep(rand(1, 5));
echo "Finalizando a thread {$this->threadId}
}
}
Classe Worker
Agrupa tarefas para serem executadas
sequencialmente
$worker = new Worker();
$worker->start();
// Empilha 9 tarefas no worker
for ($i = 0; $i < 8; ++$i) {
$worker->stack(new Task($i));
}
// Aguarda o término das tarefas
while ($worker->collect());
// Desliga o worker
$worker->shutdown();
Classe Pool
Agrupa Worker s para serem executados
concorrentemente
// Cria 3 workers que serão executados simultaneamen
$pool = new Pool(3);
// Submete 9 tarefas para o pool
for ($i = 0; $i < 8; ++$i) {
$pool->submit(new Task($i));
}
// Aguarda o término das tarefas
while ($pool->collect());
// Desliga todos os workers
$pool->shutdown();
Pontos de atenção
Tenha cuidado ao realizar operações atômicas (métodos
synchronized , notify e wait )
Nem toda tarefa ganha performance ao ser dividida em
threads
Não se esqueça de aguardar as threads terminarem
( join )
Referências
Tutorial para instalação
Slides sobre ZTS e threads no PHP (@jpauli)
Tutorial sobre pthreads (SitePoint)
Tutorial sobre pthreads v2 x v3 (SitePoint)
Manual do PHP: php.net/pthreads
Demonstração
Reutilização
Criando códigos que rodem em mais de um ambiente
Boas práticas
Deixe seu código limpo e organizado para facilitar o entendimento
PHP CodeSniffer
Detecta e corrige violações de acordo com um padrão de
regras (por exemplo, PSR-2)
PHP Mess Detector
Analisador diversos aspectos, como variáveis
desnecessárias, códigos muito complexos, etc
SOLID
Cinco princípios para deixar softwares mais entendíveis,
exíveis e de fácil manutenção
Object Calisthenics
Conjunto de 9 regras para auxiliar na manutenção,
legibilidade e facilidade de teste
Con gurações
Como armazenar parâmetros, credenciais e
outras opções?
12 Factor Apps: III. Con g - Store con g in the environment
Arquivos PHP (com simples arrays, por exemplo)
// index.php
$config = require 'config.php';
$dbh = new PDO(
$config['db']['dsn'],
$config['db']['user'],
$config['db']['pass']
);
// config.php
return [
'db' => [
'dsn' => 'mysql:dbname=mydb;host=localhost'
'user' => 'user',
'pass' => 'my@p4ssw0rd'
]
];
Injeção de dependências
Aumentando a reusabilidade de seus
códigos
Interfaces
Dependa de Interfaces ao invés de classes (mesmo que
abstratas)
Containers
PSR-11 - Containers: https://github.com/php- g/ g-
standards/blob/master/accepted/PSR-11-container.md
The PHP League Container:
https://github.com/thephpleague/container
class MyClass
{
protected $logger;
public function __construct(PsrLogLoggerInter
{
$this->logger = $logger;
}
public function run()
{
$this->logger->notice('...');
}
}
// PsrContainerContainerInterface
$container = require 'container.php';
$myClass = new MyClass(
$container->get(PsrLogLoggerInterface::class)
);
Obrigado!
GitHub
@vcampitelli
Twitter
@vcampitelli
Slides
viniciuscampitelli.com/slides/php-fora-da-web
PHP fora da Web
Utilizando nossa linguagem preferida ♥ para criar scripts CLI e robôs
Quem sou eu?
Vinícius Campitelli
@vcampitelli
@MediaPost e MT4 Tecnologia
Curseduca

Mais conteúdo relacionado

Mais procurados

PHP Experience 2016 - [Palestra] Keynote: PHP-7
PHP Experience 2016 - [Palestra] Keynote: PHP-7PHP Experience 2016 - [Palestra] Keynote: PHP-7
PHP Experience 2016 - [Palestra] Keynote: PHP-7iMasters
 
Introdução ao Shell Script (versão estendida)
Introdução ao Shell Script (versão estendida)Introdução ao Shell Script (versão estendida)
Introdução ao Shell Script (versão estendida)Hugo Maia Vieira
 
Curso de Java: Introdução a lambda e Streams
Curso de Java: Introdução a lambda e StreamsCurso de Java: Introdução a lambda e Streams
Curso de Java: Introdução a lambda e StreamsHelder da Rocha
 
Threads 07: Sincronizadores
Threads 07: SincronizadoresThreads 07: Sincronizadores
Threads 07: SincronizadoresHelder da Rocha
 
Minicurso Shell Script
Minicurso Shell ScriptMinicurso Shell Script
Minicurso Shell ScriptLuís Eduardo
 
Introducao ao Shell Script
Introducao ao Shell ScriptIntroducao ao Shell Script
Introducao ao Shell ScriptHugo Maia Vieira
 
Introdução ao Zend Framework 2
Introdução ao Zend Framework 2Introdução ao Zend Framework 2
Introdução ao Zend Framework 2Elton Minetto
 
12 aula - shell script-2015
12   aula - shell script-201512   aula - shell script-2015
12 aula - shell script-2015Flávia Santos
 
Threads 10: CompletableFuture
Threads 10: CompletableFutureThreads 10: CompletableFuture
Threads 10: CompletableFutureHelder da Rocha
 
LabMM4 (T13 - 12/13) - Funções
LabMM4 (T13 - 12/13) - FunçõesLabMM4 (T13 - 12/13) - Funções
LabMM4 (T13 - 12/13) - FunçõesCarlos Santos
 
Threads 04 Variáveis atômicas
Threads 04 Variáveis atômicasThreads 04 Variáveis atômicas
Threads 04 Variáveis atômicasHelder da Rocha
 
Soa cap2 exercicios resolvidos shell
Soa cap2 exercicios resolvidos shellSoa cap2 exercicios resolvidos shell
Soa cap2 exercicios resolvidos shellportal_Do_estudante
 

Mais procurados (20)

PHP Experience 2016 - [Palestra] Keynote: PHP-7
PHP Experience 2016 - [Palestra] Keynote: PHP-7PHP Experience 2016 - [Palestra] Keynote: PHP-7
PHP Experience 2016 - [Palestra] Keynote: PHP-7
 
Introdução ao Shell Script (versão estendida)
Introdução ao Shell Script (versão estendida)Introdução ao Shell Script (versão estendida)
Introdução ao Shell Script (versão estendida)
 
Shell script
Shell scriptShell script
Shell script
 
Curso de Java: Introdução a lambda e Streams
Curso de Java: Introdução a lambda e StreamsCurso de Java: Introdução a lambda e Streams
Curso de Java: Introdução a lambda e Streams
 
Threads 07: Sincronizadores
Threads 07: SincronizadoresThreads 07: Sincronizadores
Threads 07: Sincronizadores
 
Minicurso Shell Script
Minicurso Shell ScriptMinicurso Shell Script
Minicurso Shell Script
 
servlet-respostas
servlet-respostasservlet-respostas
servlet-respostas
 
Introducao ao Shell Script
Introducao ao Shell ScriptIntroducao ao Shell Script
Introducao ao Shell Script
 
OOP ObjC
OOP ObjCOOP ObjC
OOP ObjC
 
Introdução ao Zend Framework 2
Introdução ao Zend Framework 2Introdução ao Zend Framework 2
Introdução ao Zend Framework 2
 
12 aula - shell script-2015
12   aula - shell script-201512   aula - shell script-2015
12 aula - shell script-2015
 
Threads 09: Paralelismo
Threads 09: ParalelismoThreads 09: Paralelismo
Threads 09: Paralelismo
 
Tutorial Shell Script
Tutorial Shell ScriptTutorial Shell Script
Tutorial Shell Script
 
Lista de exercícios em Bash (resolvida)
Lista de exercícios em Bash (resolvida) Lista de exercícios em Bash (resolvida)
Lista de exercícios em Bash (resolvida)
 
Threads 10: CompletableFuture
Threads 10: CompletableFutureThreads 10: CompletableFuture
Threads 10: CompletableFuture
 
LabMM4 (T13 - 12/13) - Funções
LabMM4 (T13 - 12/13) - FunçõesLabMM4 (T13 - 12/13) - Funções
LabMM4 (T13 - 12/13) - Funções
 
Javascript
JavascriptJavascript
Javascript
 
Threads 04 Variáveis atômicas
Threads 04 Variáveis atômicasThreads 04 Variáveis atômicas
Threads 04 Variáveis atômicas
 
Palestra cbq
Palestra cbqPalestra cbq
Palestra cbq
 
Soa cap2 exercicios resolvidos shell
Soa cap2 exercicios resolvidos shellSoa cap2 exercicios resolvidos shell
Soa cap2 exercicios resolvidos shell
 

Semelhante a PHP fora da Web

Oficina de shell script
Oficina de shell scriptOficina de shell script
Oficina de shell scriptbrunobione
 
Introdução ao processamento paralelo com o Grand Central Dispatch
Introdução ao processamento paralelo com o Grand Central DispatchIntrodução ao processamento paralelo com o Grand Central Dispatch
Introdução ao processamento paralelo com o Grand Central Dispatchflisolmaringa
 
Aprendendo objective c - parte 1
Aprendendo objective c - parte 1Aprendendo objective c - parte 1
Aprendendo objective c - parte 1Alamo Saravali
 
Escrevendo modulos python com rust
Escrevendo modulos python com rustEscrevendo modulos python com rust
Escrevendo modulos python com rustBruno Rocha
 
Entre na fila. Processamento distribuído usando Gearman
Entre na fila. Processamento distribuído usando GearmanEntre na fila. Processamento distribuído usando Gearman
Entre na fila. Processamento distribuído usando GearmanElton Minetto
 
Desenvolvimento Rápido de Programas Linha de Comando
Desenvolvimento Rápido de Programas Linha de ComandoDesenvolvimento Rápido de Programas Linha de Comando
Desenvolvimento Rápido de Programas Linha de Comandogarux
 
Oficina PostgreSQL Básico Latinoware 2012
Oficina PostgreSQL Básico Latinoware 2012Oficina PostgreSQL Básico Latinoware 2012
Oficina PostgreSQL Básico Latinoware 2012Fabrízio Mello
 
Qualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitQualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitDiego Tremper
 
Linux4all#2
Linux4all#2Linux4all#2
Linux4all#2Daniel
 
TDC2016SP - Trilha Node.Js
TDC2016SP - Trilha Node.JsTDC2016SP - Trilha Node.Js
TDC2016SP - Trilha Node.Jstdc-globalcode
 
O Que é shell - bash
O Que é shell - bashO Que é shell - bash
O Que é shell - bashSérgio Silva
 
Curso Desenvolvimento WEB com PHP - PHP (parte 1)
Curso Desenvolvimento WEB com PHP - PHP (parte 1)Curso Desenvolvimento WEB com PHP - PHP (parte 1)
Curso Desenvolvimento WEB com PHP - PHP (parte 1)Willian Magalhães
 
55 New Things in Java 7 - Brazil
55 New Things in Java 7 - Brazil55 New Things in Java 7 - Brazil
55 New Things in Java 7 - BrazilStephen Chin
 
Desenvolvendo Extensões PECL
Desenvolvendo Extensões PECLDesenvolvendo Extensões PECL
Desenvolvendo Extensões PECLW3P Projetos Web
 
Ecosistema spring a_plataforma_enterprise_jav
Ecosistema spring a_plataforma_enterprise_javEcosistema spring a_plataforma_enterprise_jav
Ecosistema spring a_plataforma_enterprise_javJulio Viegas
 

Semelhante a PHP fora da Web (20)

Oficina de shell script
Oficina de shell scriptOficina de shell script
Oficina de shell script
 
Introdução ao processamento paralelo com o Grand Central Dispatch
Introdução ao processamento paralelo com o Grand Central DispatchIntrodução ao processamento paralelo com o Grand Central Dispatch
Introdução ao processamento paralelo com o Grand Central Dispatch
 
Doctrine2 Seminário PHP
Doctrine2 Seminário PHPDoctrine2 Seminário PHP
Doctrine2 Seminário PHP
 
Aprendendo objective c - parte 1
Aprendendo objective c - parte 1Aprendendo objective c - parte 1
Aprendendo objective c - parte 1
 
Palestra2009
Palestra2009Palestra2009
Palestra2009
 
Escrevendo modulos python com rust
Escrevendo modulos python com rustEscrevendo modulos python com rust
Escrevendo modulos python com rust
 
Doctrine for Dummies
Doctrine for DummiesDoctrine for Dummies
Doctrine for Dummies
 
Entre na fila. Processamento distribuído usando Gearman
Entre na fila. Processamento distribuído usando GearmanEntre na fila. Processamento distribuído usando Gearman
Entre na fila. Processamento distribuído usando Gearman
 
Desenvolvimento Rápido de Programas Linha de Comando
Desenvolvimento Rápido de Programas Linha de ComandoDesenvolvimento Rápido de Programas Linha de Comando
Desenvolvimento Rápido de Programas Linha de Comando
 
Oficina PostgreSQL Básico Latinoware 2012
Oficina PostgreSQL Básico Latinoware 2012Oficina PostgreSQL Básico Latinoware 2012
Oficina PostgreSQL Básico Latinoware 2012
 
Qualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitQualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnit
 
Linux4all#2
Linux4all#2Linux4all#2
Linux4all#2
 
TDC2016SP - Trilha Node.Js
TDC2016SP - Trilha Node.JsTDC2016SP - Trilha Node.Js
TDC2016SP - Trilha Node.Js
 
Dev Ext PHP
Dev Ext PHPDev Ext PHP
Dev Ext PHP
 
Php curl - Coleta de dados na web
Php curl - Coleta de dados na webPhp curl - Coleta de dados na web
Php curl - Coleta de dados na web
 
O Que é shell - bash
O Que é shell - bashO Que é shell - bash
O Que é shell - bash
 
Curso Desenvolvimento WEB com PHP - PHP (parte 1)
Curso Desenvolvimento WEB com PHP - PHP (parte 1)Curso Desenvolvimento WEB com PHP - PHP (parte 1)
Curso Desenvolvimento WEB com PHP - PHP (parte 1)
 
55 New Things in Java 7 - Brazil
55 New Things in Java 7 - Brazil55 New Things in Java 7 - Brazil
55 New Things in Java 7 - Brazil
 
Desenvolvendo Extensões PECL
Desenvolvendo Extensões PECLDesenvolvendo Extensões PECL
Desenvolvendo Extensões PECL
 
Ecosistema spring a_plataforma_enterprise_jav
Ecosistema spring a_plataforma_enterprise_javEcosistema spring a_plataforma_enterprise_jav
Ecosistema spring a_plataforma_enterprise_jav
 

PHP fora da Web

  • 1. Roteiro Scripts CLI Lidando com argumentos, streams e roteamento de comandos1. Robôs Gerenciando início e término de robôs, usando pcntl ou pthreads2. Reutilização Criando códigos que rodem em mais de um ambiente3.
  • 2. É a melhor solução para o meu problema? Primeiro, considere se você está usando as melhores ferramentas para cada tipo de trabalho
  • 3. Scripts CLI Criando utilitários para a linha de comando
  • 4. Argumentos As variáveis $argc e $argv guardam informações sobre os argumentos do script $argv é um array com os argumentos passados, sendo que o índice 0 contém o nome do script invocado if ($argc == 1) { echo "Uso: php {$argv[0]} <comando>" . PHP_EOL; exit(2); } switch ($argv[1]) { case 'run': // ... break; default: // ... break; }
  • 5. getopt() array getopt( string $options [, array $longopts [, int &$optind ]] ) As opções podem ser: Caracteres individuais: não aceitam valores Caracteres seguidos por um dois-pontos: valor obrigatório Caracteres seguidos por dois dois-pontos: valor opcional $options = getopt( 'ab:c::', ['verbose', 'user:', 'password::'] ); // php getopt.php -a -b valor -c1 --verbose // --user root --password array(6) { ["a"] => bool(false) ["b"] => string(5) "valor" ["c"] => string(1) "1" ["verbose"] => bool(false) ["user"] => string(4) "root" ["password"] => bool(false) }
  • 6. I/O Streams Uso das funções fopen , fgets , fputs , stream_get_line e diversas outras Disponibilização das constantes STDIN , STDOUT e STDERR // Leitura do STDIN echo "Qual seu nome? "; $line = trim(fgets(STDIN)); echo "Bem-vindo, {$line}." . PHP_EOL; // Saída para STDERR fputs(STDERR, 'Erro no sistema');
  • 7. Streams Uso de funções como stream_context_create , stream_copy_to_stream , stream_filter_append , entre outras Referências Manual do PHP: php.net/stream Palestra do Alexandre Gaigalas na PHP Experience em 2016 // Exemplo simples do poder das streams stream_filter_append(STDERR, 'string.toupper'); stream_copy_to_stream(STDIN, STDERR);
  • 8. Roteamento de comandos Organize seu script para que ele seja modular Crie estrutura de controllers para facilitar a manutenção if ($argc != 3) { echo "Uso: {$argv[0]} " . PHP_EOL; exit(2); } include 'vendor/autoload.php'; array_shift($argv); // nome do script $module = array_shift($argv); // ou $options['module $class = "MyCliControllers{$module}"; if (!class_exists($class)) { throw new DomainException("Módulo {$module} não } $command = array_shift($argv); // ou $options['comma if (!method_exists($class, $command)) { throw new DomainException("Comando {$command} nã } (new $class())->{$command}($argv); // ou $options
  • 9. Bibliotecas ZendConsole Retirado da documentação o cial // config/autoload/*.php return [ 'console' => [ 'router' => [ 'routes' => [ 'user-reset-password' => [ 'options' => [ 'route' => 'user resetpassword [--verbose|-v] <em 'defaults' => [ 'controller' => ApplicationControllerIndexCont 'action' => 'resetpassword' ] ] ] ] ] ] ];
  • 10. Bibliotecas ZendConsole use ZendMvcControllerAbstractActionController; class IndexController extends AbstractActionController { public function resetpasswordAction() { $request = $this->getRequest(); if (! $request instanceof ZendConsoleRequest) { throw new RuntimeException('Requisição inválida'); } $email = $request->getParam('email'); /* ... */ if ($request->getParam('verbose') || $request->getParam('v')) { /* ... */ } return 'Senha enviada com sucesso'; } } Adaptado da documentação o cial
  • 11. Bibliotecas Symfony Console // application.php require __DIR__.'/vendor/autoload.php'; $application = new SymfonyComponentConsoleApplication(); $application->add(new AppCommandCreateUserCommand()); $application->run(); Adaptado da documentação o cial
  • 12. Bibliotecas Symfony Console Adaptado da documentação o cial // src/Command/CreateUserCommand.php namespace AppCommand; use SymfonyComponentConsoleCommandCommand; use SymfonyComponentConsoleInputInputInterface; use SymfonyComponentConsoleOutputOutputInterface; class CreateUserCommand extends Command { protected function configure() { /* ... */ } protected function execute(InputInterface $input, OutputInterface $outpu { /* ... */ } }
  • 13. Bibliotecas Symfony Console protected function configure() { $this // Nome do comando, executado pelo bin/console ->setName('app:create-user') // Descrição do comando ao executar bin/console list ->setDescription('Cria um novo usuário.') // Descrição completa ao invocar o --help ->setHelp('Esse comando permite você criar um novo usuário...') // Argumento obrigatório ->addArgument( 'username', SymfonyComponentConsoleInputInputArgument::REQUIRED, 'Nome de usuário' ); } Adaptado da documentação o cial
  • 14. Bibliotecas Symfony Console Adaptado da documentação o cial protected function execute(InputInterface $input, OutputInterface $output) { // Imprime várias linhas (automaticamente adicionando n) $output->writeln([ 'Criando usuário', '===============', '', ]); // Imprime sem n $output->write('Nome de usuário: '); $output->write($input->getArgument('username')); }
  • 15. Bibliotecas Outras opções Laravel Zero CLImate Aura.Cli CLIFramework
  • 16. Robôs Usando o PHP para criar daemons
  • 17. Gerenciador de robôs Para iniciar, terminar e acompanhar a execução Ou você pode ter daemons "auto-executáveis" - por exemplo, diretamente via cron interface DaemonManagerInterface { // Inicia todos os daemons public function start(); // Inicia um daemon específico public function startDaemon($class); // Para todos os daemons public function stop(); // Para um daemon específico public function stopDaemon($class); // Lista os daemons que devem ser iniciados protected function getActive(); // Monitora o status de cada daemon protected function watchStatus(); }
  • 18. pcntl Extensão Process Control Manual do PHP: php.net/pcntl pcntl_fork(); // Faz um fork do processo atual pcntl_signal_dispatch(); // Invoca os handlers para pcntl_signal(); // Instala um handler pcntl_sigprocmask(); // Bloqueia/desbloqueia sinais pcntl_sigtimedwait(); // Espera por um sinal, com ti pcntl_sigwaitinfo(); // Espera por um sinal pcntl_wait(); // Aguarda/retorna o status de um filh pcntl_waitpid(); // Aguarda/retorna o status de um f
  • 19. Fluxo simples de execução Utilizando pcntl_fork() Fazendo fork do processo atual public function startDaemon($class) { $pid = pcntl_fork(); if ($pid == -1) { throw new RuntimeException("Houve um erro no } if ($pid) { // Processo pai return $pid; } // Processo filho (robô) $daemon = new $class(); $daemon->run(); die(); }
  • 20. Fluxo simples de execução Utilizando pcntl_waitpid() int pcntl_waitpid( int $pid , int &$status [, int $options = 0 [, array &$rusage ]] ) protected function watchStatus() { $count = count($this->pool); while ($count > 0) { foreach ($this->pool as $index => $pid) { // Retorna o PID do filho se ele estiver if (pcntl_waitpid($pid, $status, WNOHANG unset($this->pool[$index]); echo "Filho {$index} morreu..." . PH --$count; } } sleep(1); } }
  • 21. Fluxo simples de execução Utilizando sinais Para lidar com eventos externos pcntl_signal(SIGINT, [$this, 'signalHandler']); // Para SIGTERM, SIGINT, SIGHUP, SIGUSR1, etc public function signalHandler($signal) { switch ($signal) { case SIGTERM: case SIGINT: case SIGHUP: echo 'Terminando graciosamente...'; die(); case SIGUSR1: echo "Capturado sinal SIGUSR1 " . PHP_EO break; /* ... */ } }
  • 23. pthreads Biblioteca que implementa o padrão POSIX Threads A V3 foi totalmente reescrita para uso no PHP 7.2 Necessita do PHP compilado com ZTS (Zend Thread Safety) Classes disponíveis Threaded Thread Worker Collectable Modifiers Pool Mutex Cond Volatile
  • 24. Classe Thread Ela deve implementar o método run() class Task extends Thread { private $threadId; public function __construct($threadId) { $this->threadId = (int) $threadId; } public function run() { echo "Iniciando a thread {$this->threadId}" sleep(rand(1, 5)); echo "Finalizando a thread {$this->threadId} } }
  • 25. Classe Worker Agrupa tarefas para serem executadas sequencialmente $worker = new Worker(); $worker->start(); // Empilha 9 tarefas no worker for ($i = 0; $i < 8; ++$i) { $worker->stack(new Task($i)); } // Aguarda o término das tarefas while ($worker->collect()); // Desliga o worker $worker->shutdown();
  • 26. Classe Pool Agrupa Worker s para serem executados concorrentemente // Cria 3 workers que serão executados simultaneamen $pool = new Pool(3); // Submete 9 tarefas para o pool for ($i = 0; $i < 8; ++$i) { $pool->submit(new Task($i)); } // Aguarda o término das tarefas while ($pool->collect()); // Desliga todos os workers $pool->shutdown();
  • 27. Pontos de atenção Tenha cuidado ao realizar operações atômicas (métodos synchronized , notify e wait ) Nem toda tarefa ganha performance ao ser dividida em threads Não se esqueça de aguardar as threads terminarem ( join ) Referências Tutorial para instalação Slides sobre ZTS e threads no PHP (@jpauli) Tutorial sobre pthreads (SitePoint) Tutorial sobre pthreads v2 x v3 (SitePoint) Manual do PHP: php.net/pthreads
  • 29. Reutilização Criando códigos que rodem em mais de um ambiente
  • 30. Boas práticas Deixe seu código limpo e organizado para facilitar o entendimento PHP CodeSniffer Detecta e corrige violações de acordo com um padrão de regras (por exemplo, PSR-2) PHP Mess Detector Analisador diversos aspectos, como variáveis desnecessárias, códigos muito complexos, etc SOLID Cinco princípios para deixar softwares mais entendíveis, exíveis e de fácil manutenção Object Calisthenics Conjunto de 9 regras para auxiliar na manutenção, legibilidade e facilidade de teste
  • 31. Con gurações Como armazenar parâmetros, credenciais e outras opções? 12 Factor Apps: III. Con g - Store con g in the environment Arquivos PHP (com simples arrays, por exemplo) // index.php $config = require 'config.php'; $dbh = new PDO( $config['db']['dsn'], $config['db']['user'], $config['db']['pass'] ); // config.php return [ 'db' => [ 'dsn' => 'mysql:dbname=mydb;host=localhost' 'user' => 'user', 'pass' => 'my@p4ssw0rd' ] ];
  • 32. Injeção de dependências Aumentando a reusabilidade de seus códigos Interfaces Dependa de Interfaces ao invés de classes (mesmo que abstratas) Containers PSR-11 - Containers: https://github.com/php- g/ g- standards/blob/master/accepted/PSR-11-container.md The PHP League Container: https://github.com/thephpleague/container class MyClass { protected $logger; public function __construct(PsrLogLoggerInter { $this->logger = $logger; } public function run() { $this->logger->notice('...'); } } // PsrContainerContainerInterface $container = require 'container.php'; $myClass = new MyClass( $container->get(PsrLogLoggerInterface::class) );
  • 34. PHP fora da Web Utilizando nossa linguagem preferida ♥ para criar scripts CLI e robôs
  • 35. Quem sou eu? Vinícius Campitelli @vcampitelli @MediaPost e MT4 Tecnologia Curseduca