SlideShare uma empresa Scribd logo
PHP ao Extremo
Quem sou eu???


• github.com/thiagophx
• @thiagophx
• thiagorigo.com
• phpml.org
Agenda


• pecl/operator
• pecl/runkit *
• SplTypes
• php5.3.99-dev
<?php

class CarrinhoCompras
{
    protected $produtos;

    public function __construct()
    {
        $this->produtos = array();
    }

    public function addProduto($produto)
    {
        $this->produtos[] = $produto;
    }
}

$obj1 = new CarrinhoCompras();
$obj1->addProduto(new StdClass());
$obj1->addProduto(new StdClass());

$obj2 = new CarrinhoCompras();
$obj2->addProduto(new StdClass());
$obj2->addProduto(new StdClass());

echo $obj1 + $obj2;
<?php

class CarrinhoCompras
{
    protected $produtos;

    public function __construct()
    {
        $this->produtos = array();
    }

    public function addProduto($produto)
    {
        $this->produtos[] = $produto;
    }
}

$obj1 = new CarrinhoCompras();
$obj1->addProduto(new StdClass());
$obj1->addProduto(new StdClass());

$obj2 = new CarrinhoCompras();
$obj2->addProduto(new StdClass());
$obj2->addProduto(new StdClass());

echo $obj1 + $obj2;

// Notice: Object of class CarrinhoCompras could not be converted to int...
<?php

class CarrinhoCompras
{
    protected $produtos;

    public function __construct()
    {
        $this->produtos = array();
    }

    public function addProduto($produto)
    {
        $this->produtos[] = $produto;
    }

    public function count()
    {
        return count($this->produtos);
    }
}

$obj1 = new CarrinhoCompras();
$obj1->addProduto(new StdClass());
$obj1->addProduto(new StdClass());

$obj2 = new CarrinhoCompras();
$obj2->addProduto(new StdClass());
$obj2->addProduto(new StdClass());

echo $obj1->count() + $obj2->count();
<?php

class CarrinhoCompras implements Countable
{
    protected $produtos;

    public function __construct()
    {
        $this->produtos = array();
    }

    public function addProduto($produto)
    {
        $this->produtos[] = $produto;
    }

    public function count()
    {
        return count($this->produtos);
    }
}

$obj1 = new CarrinhoCompras();
$obj1->addProduto(new StdClass());
$obj1->addProduto(new StdClass());

$obj2 = new CarrinhoCompras();
$obj2->addProduto(new StdClass());
$obj2->addProduto(new StdClass());

echo count($obj1) + count($obj2);
Porque isso funciona?

     <?php

     $d1 = new DateTime();
     $d2 = new DateTime('1991-10-21');

     var_dump($d1 > $d2);
<?php

class CarrinhoCompras
{
    protected $produtos;

    public function __construct()
    {
        $this->produtos = array();
    }

    public function addProduto($produto)
    {
        $this->produtos[] = $produto;
    }
}

$obj1 = new CarrinhoCompras();
$obj1->addProduto(new StdClass());
$obj1->addProduto(new StdClass());

$obj2 = new CarrinhoCompras();
$obj2->addProduto(new StdClass());
$obj2->addProduto(new StdClass());
$obj2->addProduto(new StdClass());

var_dump($obj1 > $obj2);
Sobrecarga de operador
sudo pecl install -f operator
<?php

class CarrinhoCompras
{
    protected $produtos;

    public function __construct()
    {
        $this->produtos = array();
    }

    public function addProduto($produto)
    {
        $this->produtos[] = $produto;
    }

    public function __add(CarrinhoCompras $carrinho = null)
    {
        return count($this->produtos) + ($carrinho ? $carrinho->__add() : 0);
    }
}

$obj1 = new CarrinhoCompras();
$obj1->addProduto(new StdClass());
$obj1->addProduto(new StdClass());

$obj2 = new CarrinhoCompras();
$obj2->addProduto(new StdClass());
$obj2->addProduto(new StdClass());

echo $obj1 + $obj2;
<?php

interface Summable
{
    public function __add(Summable $value = null);
}

class CarrinhoCompras implements Summable
{
    protected $produtos;

    public function __construct()
    {
        $this->produtos = array();
    }

    public function addProduto($produto)
    {
        $this->produtos[] = $produto;
    }

    public function __add(Summable $value = null)
    {
        return count($this->produtos) + ($value ? $value->__add() : 0);
    }
}

$obj1 = new CarrinhoCompras();
$obj1->addProduto(new StdClass());
$obj1->addProduto(new StdClass());

$obj2 = new CarrinhoCompras();
$obj2->addProduto(new StdClass());
$obj2->addProduto(new StdClass());

echo $obj1 + $obj2;
<?php

class CarrinhoCompras
{
    protected $produtos;

    public function __construct()
    {
        $this->produtos = array();
    }

    public function addProduto($produto)
    {
        $this->produtos[] = $produto;
    }

    public function __add(CarrinhoCompras $carrinho = null)
    {
        return count($this->produtos) + ($carrinho ? $carrinho->__add() : 0);
    }
}

$obj1 = new CarrinhoCompras();
$obj1->addProduto(new StdClass());

$obj2 = new CarrinhoCompras();
$obj2->addProduto(new StdClass());

$obj3 = new CarrinhoCompras();
$obj3->addProduto(new StdClass());

var_dump($obj1 + $obj2 + $obj3);

// ???
<?php

class CarrinhoCompras
{
    protected $produtos;

    public function __construct()
    {
        $this->produtos = array();
    }

    public function addProduto($produto)
    {
        $this->produtos[] = $produto;
    }

    public function __add(CarrinhoCompras $carrinho = null)
    {
        return count($this->produtos) + ($carrinho ? $carrinho->__add() : 0);
    }
}

$obj1 = new CarrinhoCompras();
$obj1->addProduto(new StdClass());

$obj2 = new CarrinhoCompras();
$obj2->addProduto(new StdClass());

$obj3 = new CarrinhoCompras();
$obj3->addProduto(new StdClass());

var_dump($obj1 + $obj2 + $obj3);

// Notice:   Object of class CarrinhoCompras could not be converted to int...
<?php

class CarrinhoCompras
{
    protected $produtos;

    public function __construct()
    {
        $this->produtos = array();
    }

    public function addProduto($produto)
    {
        $this->produtos[] = $produto;
    }

    public function __add($value = null)
    {
        if (is_int($value))
            return count($this->produtos) + $value;

        return count($this->produtos) + ($value ? $value->__add() : 0);
    }
}

$obj1 = new CarrinhoCompras();
$obj1->addProduto(new StdClass());

$obj2 = new CarrinhoCompras();
$obj2->addProduto(new StdClass());

$obj3 = new CarrinhoCompras();
$obj3->addProduto(new StdClass());

var_dump($obj1 + ($obj2 + $obj3));
Exemplo do mundo real
<?php

class ContaCorrente // Entity
{
    public function depositar(Dinheiro $valor)
    {
        $this->setSaldo($this->getSaldo() + $valor);
    }
}

class Dinheiro // ValueObject
{
    const BRL = 1;
    const AUD = 2;

    protected $tipoMoeda;

    public function getTipoMoeda() { ... }

    public function converte($tipoMoeda)
    {
        return $this->getValor() * $tipoMoeda;
    }

    public function __add($dinheiro)
    {
        return $this->getValor() + $dinheiro->convert($this->getTipoMoeda());
    }
}

$conta = new ContaCorrente(/* id */);
$valor = new Dinheiro(100);
$conta->depositar($valor);
Operadores disponíveis


   +, -, *, /, %, <<, >>, ., |, &, ^, ~, !, ++, --, +=, -=, *=,
/=, %=, <<=, >>=, .=, |=, &=, ^=, ~=, ==, !=, ===, !==, <, <=
Nada é perfeito...



• Só funciona no 5.2
Injeção de Dependência
Injeção de Dependência
 <?php

 // Zend Framework: A setter injection example
 $transport = new Zend_Mail_Transport_Smtp('smtp.gmail.com', array(
   'auth'     => 'login',
   'username' => 'foo',
   'password' => 'bar',
   'ssl'      => 'ssl',
   'port'     => 465,
 ));
  
 $mailer = new Zend_Mail();
 $mailer->setDefaultTransport($transport);
Container de Injeção de Dependência
Symfony
<?xml version="1.0" ?>
 
<container xmlns="http://symfony-project.org/2.0/container">
  <parameters>
    <parameter key="mailer.username">foo</parameter>
    <parameter key="mailer.password">bar</parameter>
    <parameter key="mailer.class">Zend_Mail</parameter>
  </parameters>
  <services>
    <service id="mail.transport" class="Zend_Mail_Transport_Smtp" shared="false">
      <argument>smtp.gmail.com</argument>
      <argument type="collection">
        <argument key="auth">login</argument>
        <argument key="username">%mailer.username%</argument>
        <argument key="password">%mailer.password%</argument>
        <argument key="ssl">ssl</argument>
        <argument key="port">465</argument>
      </argument>
    </service>
    <service id="mailer" class="%mailer.class%">
      <call method="setDefaultTransport">
        <argument type="service" id="mail.transport" />
      </call>
    </service>
  </services>
</container>
Symfony

<?php
require_once '/PATH/TO/sfServiceContainerAutoloader.php';
sfServiceContainerAutoloader::register();
 
$sc = new sfServiceContainerBuilder();
 
$loader = new sfServiceContainerLoaderFileXml($sc);
$loader->load('/somewhere/container.xml');
$sc->mailer;
Inversão de Controle
Você não chama, você é chamado!
<?php

class UserService
{
    protected $serviceLocator;

    public function __construct($serviceLocator)
    {
        $this->serviceLocator = $serviceLocator;
    }

    public function saveUser(array $data)
    {
        $validator = $this->serviceLocator->getService('validator');

        try {
            // Valida os dados
            $data = $validator->validate($data);

            $repository = new UserRepository();
            $user = new User();

            // Persiste os dados
            return $repository->save($data, $user);

        } catch (Exception $e) {
            $this->serviceLocator->getService('logger')->log($e);
        }

        return null;
    }
}
<?php

class UserService
{
    /**
     * @Dependency(validator)
     */
    protected $validator;

    /**
     * @Dependency(logger)
     */
    protected $logger;

    public function saveUser(array $data)
    {
        try {
            // Valida os dados
            $data = $this->validator->validate($data);

            $repository = new UserRepository();
            $user = new User();

            // Persiste os dados
            return $repository->save($data, $user);

        } catch (Exception $e) {
            $this->logger->log($e);
        }

        return null;
    }
}
runkit
https://github.com/zenovich/runkit/
<?php

class Container
{
    protected static $data = array('mailer' => 'mailer');

    public static function get($key)
    {
        if (!self::exists($key))
            throw new InvalidArgumentException('Invalid key!');

        return self::$data[$key];
    }

    public static function exists($key)
    {
        return array_key_exists($key, self::$data);
    }

    public static function notify($object)
    {
        $injector = new Injector($object, self::$data);
        return $injector->inject();
    }
}
<?php

class Watcher
{
    protected $dir;

    public function __construct($dir)
    {
        $this->dir = $dir;
    }

    public function watch()
    {
        foreach (glob($this->dir . DIRECTORY_SEPARATOR . '*.php') as $class) {
            require $class;
            runkit_method_add(pathinfo($class, PATHINFO_FILENAME),
            '__construct',
            '',
            'Container::notify($this);');
        }
    }
}
<?php

class Injector
{
    protected $object;

    public function __construct($object)
    {
        $this->object = $object;
    }

    public function inject()
    {
        $reflection = new ReflectionObject($this->object);
        $prop = $reflection->getProperty('mailer');

        if (!Container::exists('mailer'))
            return null;

        $prop->setAccessible(true);
        $prop->setValue($this->object, Container::get('mailer'));
        return true;
    }
}
<?php

class Controller
{
    protected $mailer;

    public function get()
    {
        var_dump($this->mailer);
    }
}
<?php

$w = new Watcher('path/to/my/folder');
$w->watch();

$c = new Controller();
$c->get();
// string(6) "mailer"
<?php

class UserService
{
    /**
     * @Dependency(validator)
     */
    protected $validator;

    /**
     * @Dependency(logger)
     */
    protected $logger;

    public function saveUser(array $data)
    {
        try {
            // Valida os dados
            $data = $this->validator->validate($data);

            $repository = new UserRepository();
            $user = new User();

            // Persiste os dados
            return $repository->save($data, $user);

        } catch (Exception $e) {
            $this->logger->log($e);
        }

        return null;
    }
}
<?php

class AnnotationParser
{
    protected $class;

    public function __construct(ReflectionClass $class)
    {
        $this->class = $class;
    }

    public function parseDependencies()
    {
        $dependencies = array();

        foreach ($this->class->getProperties() as $prop)
            if ($this->matchDependency($prop, $matches))
                $dependencies[] = array('property' => $prop, 'dependency' => $matches[1]);

        return $dependencies;
    }

    protected function matchDependency($prop, &$matches)
    {
        return (bool) preg_match('/@dependencys*(([a-zA-Z0-9_ ]*))/i',
            $prop->getDocComment(), $matches);
    }
}
<?php

class Injector
{
    protected $object;

    public function __construct($object)
    {
        $this->object = $object;
    }

    public function inject()
    {
        $annotationParser = new AnnotationParser(new ReflectionObject($this->object));
        $props = $annotationParser->parseDependencies();

        foreach ($props as $prop) {
            if (Container::exists($prop['dependency'])) {
                $prop['property']->setAccessible(true);
                $prop['property']->setValue($this->object,
                    Container::get($prop['dependency']));
            }

        }
    }
}
<?php

class Container
{
    protected static $data = array();

    public static function set($key, $value)
    {
        self::$data[$key] = $value;
    }

    public static function get($key)
    {
        if (!self::exists($key))
            throw new InvalidArgumentException('Invalid key!');

        return self::$data[$key];
    }

    public static function exists($key)
    {
        return array_key_exists($key, self::$data);
    }

    public static function notify($object)
    {
        $injector = new Injector($object, self::$data);
        return $injector->inject();
    }
}
<?php

class Validator
{
    public function validate()
    {
        // ...
    }
}

class Logger
{
    public function log()
    {
        // ...
    }
}

$w = new Watcher('path/to/my/folder');
$w->watch();

Container::set('validator', new Validator());
Container::set('logger', new Logger());

$c = new UserService();
$c->saveUser(array());
Melhorias


• Verificar existência de __construct
• Pegar os parametros do __construct
• Observar classes dentro de
  namespaces(recursivo)
Recursos


• function_add, *_remove, *_copy,
  *_redefine, *_rename
• method_add, *_remove, *_copy,
  *_redefine, *_rename
E agora???


• Tokenizer
• Mutagenesis (https://github.com/
  padraic/mutagenesis)
Variáveis Tipadas
PHP tem tipo???
<?php

$id = $_GET['id']; // int
$valor = $_GET['valor']; // float
<?php

$id = (int) $_GET['id']; // int
$valor = (float) $_GET['valor']; // float
<?php

$id = $_GET['id']; // int
$valor = $_GET['valor']; // float

function processa($id, $valor)
{
    // ...
}
<?php

$id = $_GET['id']; // int
$valor = $_GET['valor']; // float

function processa($id, $valor)
{
    $id = (int) $id;
    $valor = (float) $valor;

    echo $id, $valor;
}

processa($id, $valor);
<?php

$id = $_GET['id']; // int
$valor = $_GET['valor']; // float

function processa($id, $valor)
{
    if (!is_int($id))
        throw new InvalidArgumentException('Tipo inválido');

    if (!is_float($valor))
        throw new InvalidArgumentException('Tipo inválido');

    echo $id, $valor;
}

processa($id, $valor);
<?php

$id = $_GET['id']; // int
$valor = $_GET['valor']; // float

function processa(Integer $id, Float $valor)
{
    echo $id, $valor;
}

processa(new Integer($id), new Float($valor));
sudo pecl install spl_types
<?php

$id = $_GET['id']; // int
$valor = $_GET['valor']; // float

function processa(SplInt $id, SplFloat $valor)
{
    echo $id, $valor;
}

processa(new SplInt($id), new SplFloat($valor));
<?php

$int = new SplInt('10');
// ?
<?php

$int = new SplInt('10');
// UnexpectedValueException: Value not an integer
<?php

$int = new SplInt('10', false);
// Ok
<?php

$int = new SplInt('10');

if (!is_int('10'))
    throw new InvalidArgumentException('Tipo inválido');



$int1 = new SplInt('10', false);
$int2 = '10';

if (!is_int($int2))
    $int2 = (int) $int2;
<?php

$int = new SplInt(10);
$int = 10;

$int1 = new SplInt('10', false);
$int1 = '10';
<?php

$int = new SplInt(10);
$float = new SplFloat(10.7);

echo    $float   +   $int;
echo    $float   -   $int;
echo    $float   /   $int;
echo    $float   *   $int;
<?php

$id = $_GET['id']; // int
$valor = $_GET['valor']; // float

function processa(SplInt $id, SplFloat $valor)
{
    echo $id, $valor;
}

processa($id, $valor);
// Catchable fatal error: Argument 1 passed to processa() must be an instance of SplInt
// Catchable fatal error: Argument 2 passed to processa() must be an instance of SplFloat
<?php

class Month extends SplEnum
{
    const __default = self::January;

    const   January = 1;
    const   February = 2;
    const   March = 3;
    const   April = 4;
    const   May = 5;
    const   June = 6;
    const   July = 7;
    const   August = 8;
    const   September = 9;
    const   October = 10;
    const   November = 11;
    const   December = 12;
}
<?php

class Month extends SplEnum
{
    const __default = self::January;

    const   January = 1;
    const   February = 2;
    const   March = 3;
    const   April = 4;
    const   May = 5;
    const   June = 6;
    const   July = 7;
    const   August = 8;
    const   September = 9;
    const   October = 10;
    const   November = 11;
    const   December = 12;
}

function getMonth(Month $month)
{
    echo $month;
}

getMonth(new Month(Month::October));
<?php

class Month extends SplEnum
{
    const __default = self::January;

    const   January = 1;
    const   February = 2;
    const   March = 3;
    const   April = 4;
    const   May = 5;
    const   June = 6;
    const   July = 7;
    const   August = 8;
    const   September = 9;
    const   October = 10;
    const   November = 11;
    const   December = 12;
}

function getMonth(Month $month)
{
    echo $month;
}

getMonth(new Month(13));
// UnexpectedValueException: Value not a const in enum Month
<?php

class Month extends SplEnum
{
    const __default = self::January;

    const   January = 1;
    const   February = 2;
    const   March = 3;
    const   April = 4;
    const   May = 5;
    const   June = 6;
    const   July = 7;
    const   August = 8;
    const   September = 9;
    const   October = 10;
    const   November = 11;
    const   December = 12;
}

$month = new Month();
var_dump($month->getConstList());
Scalar Type Hinting
<?php

function foo(array $value)
{
    // ...
}
<?php

function testInt(integer $value)
{
    var_dump($value);
}

testInt(1);
http://svn.php.net/viewvc?
view=revision&revision=299534
https://svn.php.net/repository/php/php-src/
     branches/WITH_SCALAR_TYPES/
http://ilia.ws/archives/207-Type-Hinting-
              Conclusion.html
<?php

function testInt(integer $value)
{
    var_dump($value);
}

testInt('PHPubSP');
// Catchable fatal error: Argument 1 passed to testInt() must be of the type integer,
string given
<?php

function testNumeric(numeric $value)
{
    var_dump($value);
}

testNumeric('10');
<?php

function testCast((int) $value)
{
    var_dump($value);
}

testCast('10');
<?php

function testScalar(scalar $value)
{
    var_dump($value);
}

testScalar('10');
<?php

function testBool(bool $value)
{
    // ...
}

function testString(string $value)
{
    // ...
}

function testFloat(float $value)
{
    // ...
}
Perguntas???

Mais conteúdo relacionado

KEY
PHPubSP Object Calisthenics aplicado ao PHP
PDF
PHP para Adultos: Clean Code e Object Calisthenics
PDF
Object Calisthenics: relaxe e escreva códigos simples
PDF
Proxy, Man-In-The-Middle e testes
PDF
Evento Front End SP - Organizando o Javascript
PPTX
Design patterns
PDF
LabMM4 (T11 - 12/13) - PHP - Tipos de dados e variáveis
PDF
Java script aula 05 - funções
PHPubSP Object Calisthenics aplicado ao PHP
PHP para Adultos: Clean Code e Object Calisthenics
Object Calisthenics: relaxe e escreva códigos simples
Proxy, Man-In-The-Middle e testes
Evento Front End SP - Organizando o Javascript
Design patterns
LabMM4 (T11 - 12/13) - PHP - Tipos de dados e variáveis
Java script aula 05 - funções

Mais procurados (20)

PDF
Introdução ao Respect\Validation (1.0)
PPTX
Palestra Novidades da linguagem C# 6
PDF
Programando em python dicionarios
PDF
modernizando a arquitertura de sua aplicação
PDF
Da Argila Ao Forte - Como desenvolver uma loja virtual
PDF
Minicurso de jQuery
PDF
LabMM4 (T13 - 12/13) - Funções
ODP
Clean code
PDF
Criando APIs usando o micro-framework Respect
KEY
SPL Datastructures
PDF
Php curl - Coleta de dados na web
PPTX
Introdução ao MongoDB
PDF
Java 8 - Afinal onde usamos no dia a dia? TDC 2015 - Porto Alegre
PDF
Hooks, o condimento mágico e escondido do WordPress
PDF
Java script - funções
PDF
Escrevendo plugins JQuery
PPT
Spring Capitulo 03
PDF
Criando controle de acesso com php e my sql
PPTX
Refactoring sem complicação!
ODP
Orientação a Objetos em PHP
Introdução ao Respect\Validation (1.0)
Palestra Novidades da linguagem C# 6
Programando em python dicionarios
modernizando a arquitertura de sua aplicação
Da Argila Ao Forte - Como desenvolver uma loja virtual
Minicurso de jQuery
LabMM4 (T13 - 12/13) - Funções
Clean code
Criando APIs usando o micro-framework Respect
SPL Datastructures
Php curl - Coleta de dados na web
Introdução ao MongoDB
Java 8 - Afinal onde usamos no dia a dia? TDC 2015 - Porto Alegre
Hooks, o condimento mágico e escondido do WordPress
Java script - funções
Escrevendo plugins JQuery
Spring Capitulo 03
Criando controle de acesso com php e my sql
Refactoring sem complicação!
Orientação a Objetos em PHP
Anúncio

Semelhante a PHP ao Extremo (20)

PPTX
Clean Code e Object Calisthenics - Aplicados no PHP
PDF
Ecommerce, mais simples do que parece
PDF
Ecommerce, mais simples do que parece
PDF
Bread board
PPT
Aula5
PDF
Vraptor
PPT
Curso de Introdução - PHP
PPT
ZF Básico - 6. Autenticação
PPTX
Programação web ii aulas 06 e 07
PDF
Como conectar programas em linguagem java a bases de dados
PDF
As novidades do PHP5 (2005)
PDF
Aula 12 Relatório - Tabelas
PPTX
Vraptor - Alta produtividade no Desenvolvimento Web em Java
PPTX
PHP robusto com Zend Framework
PDF
Symfony - Framework PHP de alta produtividade
PDF
Código legado - PHP Conference Brasil - 2014
PDF
PHP: Linguagem + Mysql + MVC + AJAX
PDF
Play Framework - FLISOL
PDF
PHP fora da Web
PDF
Refatoração de código com Capitão Nascimento versão completa
Clean Code e Object Calisthenics - Aplicados no PHP
Ecommerce, mais simples do que parece
Ecommerce, mais simples do que parece
Bread board
Aula5
Vraptor
Curso de Introdução - PHP
ZF Básico - 6. Autenticação
Programação web ii aulas 06 e 07
Como conectar programas em linguagem java a bases de dados
As novidades do PHP5 (2005)
Aula 12 Relatório - Tabelas
Vraptor - Alta produtividade no Desenvolvimento Web em Java
PHP robusto com Zend Framework
Symfony - Framework PHP de alta produtividade
Código legado - PHP Conference Brasil - 2014
PHP: Linguagem + Mysql + MVC + AJAX
Play Framework - FLISOL
PHP fora da Web
Refatoração de código com Capitão Nascimento versão completa
Anúncio

Último (20)

PPTX
Curso de Java 14 - (Explicações Adicionais (Classes Abstrata e Interface)).pptx
PDF
Otimizador de planejamento e execução no SAP Transportation Management, TM120...
PDF
Custos e liquidação no SAP Transportation Management, TM130 Col18
PPTX
Aula sobre banco de dados com firebase db
PPTX
Curso de Java 13 - (JavaEE (JSP e Servlets)).pptx
PPTX
Curso de Java 16 - (JEE (Utilizando o Padrão MVC)).pptx
PDF
Apple Pippin Uma breve introdução. - David Glotz
PPTX
Gestao-de-Bugs-em-Software-Introducao.pptxxxxxxxx
PPTX
BANCO DE DADOS - AULAS INICIAIS-sgbd.pptx
PDF
Processos na gestão de transportes, TM100 Col18
PPTX
Curso de Java 12 - (JDBC, Transation, Commit e Rollback).pptx
PDF
Fundamentos de gerenciamento de ordens e planejamento no SAP TransportationMa...
PPTX
Aula 18 - Manipulacao De Arquivos python
PPTX
Curso de Java 9 - (Threads) Multitarefas.pptx
PPTX
Curso de Java 17 - (JEE (Sessões e Cookies)).pptx
PDF
Mergulho profundo técnico para gestão de transportes no SAP S/4HANA, S4TM6 Col14
PPTX
Curso de Java 11 - (Serializable (Serialização de Objetos)).pptx
PPTX
Émile Durkheim slide elaborado muito bom
PDF
20250805_ServiceNow e a Arquitetura Orientada a Serviços (SOA) A Base para Ap...
PDF
Gestão de transportes básica no SAP S/4HANA, S4611 Col20
Curso de Java 14 - (Explicações Adicionais (Classes Abstrata e Interface)).pptx
Otimizador de planejamento e execução no SAP Transportation Management, TM120...
Custos e liquidação no SAP Transportation Management, TM130 Col18
Aula sobre banco de dados com firebase db
Curso de Java 13 - (JavaEE (JSP e Servlets)).pptx
Curso de Java 16 - (JEE (Utilizando o Padrão MVC)).pptx
Apple Pippin Uma breve introdução. - David Glotz
Gestao-de-Bugs-em-Software-Introducao.pptxxxxxxxx
BANCO DE DADOS - AULAS INICIAIS-sgbd.pptx
Processos na gestão de transportes, TM100 Col18
Curso de Java 12 - (JDBC, Transation, Commit e Rollback).pptx
Fundamentos de gerenciamento de ordens e planejamento no SAP TransportationMa...
Aula 18 - Manipulacao De Arquivos python
Curso de Java 9 - (Threads) Multitarefas.pptx
Curso de Java 17 - (JEE (Sessões e Cookies)).pptx
Mergulho profundo técnico para gestão de transportes no SAP S/4HANA, S4TM6 Col14
Curso de Java 11 - (Serializable (Serialização de Objetos)).pptx
Émile Durkheim slide elaborado muito bom
20250805_ServiceNow e a Arquitetura Orientada a Serviços (SOA) A Base para Ap...
Gestão de transportes básica no SAP S/4HANA, S4611 Col20

PHP ao Extremo

  • 2. Quem sou eu??? • github.com/thiagophx • @thiagophx • thiagorigo.com • phpml.org
  • 3. Agenda • pecl/operator • pecl/runkit * • SplTypes • php5.3.99-dev
  • 4. <?php class CarrinhoCompras { protected $produtos; public function __construct() { $this->produtos = array(); } public function addProduto($produto) { $this->produtos[] = $produto; } } $obj1 = new CarrinhoCompras(); $obj1->addProduto(new StdClass()); $obj1->addProduto(new StdClass()); $obj2 = new CarrinhoCompras(); $obj2->addProduto(new StdClass()); $obj2->addProduto(new StdClass()); echo $obj1 + $obj2;
  • 5. <?php class CarrinhoCompras { protected $produtos; public function __construct() { $this->produtos = array(); } public function addProduto($produto) { $this->produtos[] = $produto; } } $obj1 = new CarrinhoCompras(); $obj1->addProduto(new StdClass()); $obj1->addProduto(new StdClass()); $obj2 = new CarrinhoCompras(); $obj2->addProduto(new StdClass()); $obj2->addProduto(new StdClass()); echo $obj1 + $obj2; // Notice: Object of class CarrinhoCompras could not be converted to int...
  • 6. <?php class CarrinhoCompras { protected $produtos; public function __construct() { $this->produtos = array(); } public function addProduto($produto) { $this->produtos[] = $produto; } public function count() { return count($this->produtos); } } $obj1 = new CarrinhoCompras(); $obj1->addProduto(new StdClass()); $obj1->addProduto(new StdClass()); $obj2 = new CarrinhoCompras(); $obj2->addProduto(new StdClass()); $obj2->addProduto(new StdClass()); echo $obj1->count() + $obj2->count();
  • 7. <?php class CarrinhoCompras implements Countable { protected $produtos; public function __construct() { $this->produtos = array(); } public function addProduto($produto) { $this->produtos[] = $produto; } public function count() { return count($this->produtos); } } $obj1 = new CarrinhoCompras(); $obj1->addProduto(new StdClass()); $obj1->addProduto(new StdClass()); $obj2 = new CarrinhoCompras(); $obj2->addProduto(new StdClass()); $obj2->addProduto(new StdClass()); echo count($obj1) + count($obj2);
  • 8. Porque isso funciona? <?php $d1 = new DateTime(); $d2 = new DateTime('1991-10-21'); var_dump($d1 > $d2);
  • 9. <?php class CarrinhoCompras { protected $produtos; public function __construct() { $this->produtos = array(); } public function addProduto($produto) { $this->produtos[] = $produto; } } $obj1 = new CarrinhoCompras(); $obj1->addProduto(new StdClass()); $obj1->addProduto(new StdClass()); $obj2 = new CarrinhoCompras(); $obj2->addProduto(new StdClass()); $obj2->addProduto(new StdClass()); $obj2->addProduto(new StdClass()); var_dump($obj1 > $obj2);
  • 11. sudo pecl install -f operator
  • 12. <?php class CarrinhoCompras { protected $produtos; public function __construct() { $this->produtos = array(); } public function addProduto($produto) { $this->produtos[] = $produto; } public function __add(CarrinhoCompras $carrinho = null) { return count($this->produtos) + ($carrinho ? $carrinho->__add() : 0); } } $obj1 = new CarrinhoCompras(); $obj1->addProduto(new StdClass()); $obj1->addProduto(new StdClass()); $obj2 = new CarrinhoCompras(); $obj2->addProduto(new StdClass()); $obj2->addProduto(new StdClass()); echo $obj1 + $obj2;
  • 13. <?php interface Summable { public function __add(Summable $value = null); } class CarrinhoCompras implements Summable { protected $produtos; public function __construct() { $this->produtos = array(); } public function addProduto($produto) { $this->produtos[] = $produto; } public function __add(Summable $value = null) { return count($this->produtos) + ($value ? $value->__add() : 0); } } $obj1 = new CarrinhoCompras(); $obj1->addProduto(new StdClass()); $obj1->addProduto(new StdClass()); $obj2 = new CarrinhoCompras(); $obj2->addProduto(new StdClass()); $obj2->addProduto(new StdClass()); echo $obj1 + $obj2;
  • 14. <?php class CarrinhoCompras { protected $produtos; public function __construct() { $this->produtos = array(); } public function addProduto($produto) { $this->produtos[] = $produto; } public function __add(CarrinhoCompras $carrinho = null) { return count($this->produtos) + ($carrinho ? $carrinho->__add() : 0); } } $obj1 = new CarrinhoCompras(); $obj1->addProduto(new StdClass()); $obj2 = new CarrinhoCompras(); $obj2->addProduto(new StdClass()); $obj3 = new CarrinhoCompras(); $obj3->addProduto(new StdClass()); var_dump($obj1 + $obj2 + $obj3); // ???
  • 15. <?php class CarrinhoCompras { protected $produtos; public function __construct() { $this->produtos = array(); } public function addProduto($produto) { $this->produtos[] = $produto; } public function __add(CarrinhoCompras $carrinho = null) { return count($this->produtos) + ($carrinho ? $carrinho->__add() : 0); } } $obj1 = new CarrinhoCompras(); $obj1->addProduto(new StdClass()); $obj2 = new CarrinhoCompras(); $obj2->addProduto(new StdClass()); $obj3 = new CarrinhoCompras(); $obj3->addProduto(new StdClass()); var_dump($obj1 + $obj2 + $obj3); // Notice: Object of class CarrinhoCompras could not be converted to int...
  • 16. <?php class CarrinhoCompras { protected $produtos; public function __construct() { $this->produtos = array(); } public function addProduto($produto) { $this->produtos[] = $produto; } public function __add($value = null) { if (is_int($value)) return count($this->produtos) + $value; return count($this->produtos) + ($value ? $value->__add() : 0); } } $obj1 = new CarrinhoCompras(); $obj1->addProduto(new StdClass()); $obj2 = new CarrinhoCompras(); $obj2->addProduto(new StdClass()); $obj3 = new CarrinhoCompras(); $obj3->addProduto(new StdClass()); var_dump($obj1 + ($obj2 + $obj3));
  • 18. <?php class ContaCorrente // Entity { public function depositar(Dinheiro $valor) { $this->setSaldo($this->getSaldo() + $valor); } } class Dinheiro // ValueObject { const BRL = 1; const AUD = 2; protected $tipoMoeda; public function getTipoMoeda() { ... } public function converte($tipoMoeda) { return $this->getValor() * $tipoMoeda; } public function __add($dinheiro) { return $this->getValor() + $dinheiro->convert($this->getTipoMoeda()); } } $conta = new ContaCorrente(/* id */); $valor = new Dinheiro(100); $conta->depositar($valor);
  • 19. Operadores disponíveis +, -, *, /, %, <<, >>, ., |, &, ^, ~, !, ++, --, +=, -=, *=, /=, %=, <<=, >>=, .=, |=, &=, ^=, ~=, ==, !=, ===, !==, <, <=
  • 20. Nada é perfeito... • Só funciona no 5.2
  • 22. Injeção de Dependência <?php // Zend Framework: A setter injection example $transport = new Zend_Mail_Transport_Smtp('smtp.gmail.com', array( 'auth' => 'login', 'username' => 'foo', 'password' => 'bar', 'ssl' => 'ssl', 'port' => 465, ));   $mailer = new Zend_Mail(); $mailer->setDefaultTransport($transport);
  • 23. Container de Injeção de Dependência
  • 24. Symfony <?xml version="1.0" ?>   <container xmlns="http://symfony-project.org/2.0/container"> <parameters> <parameter key="mailer.username">foo</parameter> <parameter key="mailer.password">bar</parameter> <parameter key="mailer.class">Zend_Mail</parameter> </parameters> <services> <service id="mail.transport" class="Zend_Mail_Transport_Smtp" shared="false"> <argument>smtp.gmail.com</argument> <argument type="collection"> <argument key="auth">login</argument> <argument key="username">%mailer.username%</argument> <argument key="password">%mailer.password%</argument> <argument key="ssl">ssl</argument> <argument key="port">465</argument> </argument> </service> <service id="mailer" class="%mailer.class%"> <call method="setDefaultTransport"> <argument type="service" id="mail.transport" /> </call> </service> </services> </container>
  • 25. Symfony <?php require_once '/PATH/TO/sfServiceContainerAutoloader.php'; sfServiceContainerAutoloader::register();   $sc = new sfServiceContainerBuilder();   $loader = new sfServiceContainerLoaderFileXml($sc); $loader->load('/somewhere/container.xml'); $sc->mailer;
  • 27. Você não chama, você é chamado!
  • 28. <?php class UserService { protected $serviceLocator; public function __construct($serviceLocator) { $this->serviceLocator = $serviceLocator; } public function saveUser(array $data) { $validator = $this->serviceLocator->getService('validator'); try { // Valida os dados $data = $validator->validate($data); $repository = new UserRepository(); $user = new User(); // Persiste os dados return $repository->save($data, $user); } catch (Exception $e) { $this->serviceLocator->getService('logger')->log($e); } return null; } }
  • 29. <?php class UserService { /** * @Dependency(validator) */ protected $validator; /** * @Dependency(logger) */ protected $logger; public function saveUser(array $data) { try { // Valida os dados $data = $this->validator->validate($data); $repository = new UserRepository(); $user = new User(); // Persiste os dados return $repository->save($data, $user); } catch (Exception $e) { $this->logger->log($e); } return null; } }
  • 31. <?php class Container { protected static $data = array('mailer' => 'mailer'); public static function get($key) { if (!self::exists($key)) throw new InvalidArgumentException('Invalid key!'); return self::$data[$key]; } public static function exists($key) { return array_key_exists($key, self::$data); } public static function notify($object) { $injector = new Injector($object, self::$data); return $injector->inject(); } }
  • 32. <?php class Watcher { protected $dir; public function __construct($dir) { $this->dir = $dir; } public function watch() { foreach (glob($this->dir . DIRECTORY_SEPARATOR . '*.php') as $class) { require $class; runkit_method_add(pathinfo($class, PATHINFO_FILENAME), '__construct', '', 'Container::notify($this);'); } } }
  • 33. <?php class Injector { protected $object; public function __construct($object) { $this->object = $object; } public function inject() { $reflection = new ReflectionObject($this->object); $prop = $reflection->getProperty('mailer'); if (!Container::exists('mailer')) return null; $prop->setAccessible(true); $prop->setValue($this->object, Container::get('mailer')); return true; } }
  • 34. <?php class Controller { protected $mailer; public function get() { var_dump($this->mailer); } }
  • 35. <?php $w = new Watcher('path/to/my/folder'); $w->watch(); $c = new Controller(); $c->get(); // string(6) "mailer"
  • 36. <?php class UserService { /** * @Dependency(validator) */ protected $validator; /** * @Dependency(logger) */ protected $logger; public function saveUser(array $data) { try { // Valida os dados $data = $this->validator->validate($data); $repository = new UserRepository(); $user = new User(); // Persiste os dados return $repository->save($data, $user); } catch (Exception $e) { $this->logger->log($e); } return null; } }
  • 37. <?php class AnnotationParser { protected $class; public function __construct(ReflectionClass $class) { $this->class = $class; } public function parseDependencies() { $dependencies = array(); foreach ($this->class->getProperties() as $prop) if ($this->matchDependency($prop, $matches)) $dependencies[] = array('property' => $prop, 'dependency' => $matches[1]); return $dependencies; } protected function matchDependency($prop, &$matches) { return (bool) preg_match('/@dependencys*(([a-zA-Z0-9_ ]*))/i', $prop->getDocComment(), $matches); } }
  • 38. <?php class Injector { protected $object; public function __construct($object) { $this->object = $object; } public function inject() { $annotationParser = new AnnotationParser(new ReflectionObject($this->object)); $props = $annotationParser->parseDependencies(); foreach ($props as $prop) { if (Container::exists($prop['dependency'])) { $prop['property']->setAccessible(true); $prop['property']->setValue($this->object, Container::get($prop['dependency'])); } } } }
  • 39. <?php class Container { protected static $data = array(); public static function set($key, $value) { self::$data[$key] = $value; } public static function get($key) { if (!self::exists($key)) throw new InvalidArgumentException('Invalid key!'); return self::$data[$key]; } public static function exists($key) { return array_key_exists($key, self::$data); } public static function notify($object) { $injector = new Injector($object, self::$data); return $injector->inject(); } }
  • 40. <?php class Validator { public function validate() { // ... } } class Logger { public function log() { // ... } } $w = new Watcher('path/to/my/folder'); $w->watch(); Container::set('validator', new Validator()); Container::set('logger', new Logger()); $c = new UserService(); $c->saveUser(array());
  • 41. Melhorias • Verificar existência de __construct • Pegar os parametros do __construct • Observar classes dentro de namespaces(recursivo)
  • 42. Recursos • function_add, *_remove, *_copy, *_redefine, *_rename • method_add, *_remove, *_copy, *_redefine, *_rename
  • 43. E agora??? • Tokenizer • Mutagenesis (https://github.com/ padraic/mutagenesis)
  • 46. <?php $id = $_GET['id']; // int $valor = $_GET['valor']; // float
  • 47. <?php $id = (int) $_GET['id']; // int $valor = (float) $_GET['valor']; // float
  • 48. <?php $id = $_GET['id']; // int $valor = $_GET['valor']; // float function processa($id, $valor) { // ... }
  • 49. <?php $id = $_GET['id']; // int $valor = $_GET['valor']; // float function processa($id, $valor) { $id = (int) $id; $valor = (float) $valor; echo $id, $valor; } processa($id, $valor);
  • 50. <?php $id = $_GET['id']; // int $valor = $_GET['valor']; // float function processa($id, $valor) { if (!is_int($id)) throw new InvalidArgumentException('Tipo inválido'); if (!is_float($valor)) throw new InvalidArgumentException('Tipo inválido'); echo $id, $valor; } processa($id, $valor);
  • 51. <?php $id = $_GET['id']; // int $valor = $_GET['valor']; // float function processa(Integer $id, Float $valor) { echo $id, $valor; } processa(new Integer($id), new Float($valor));
  • 52. sudo pecl install spl_types
  • 53. <?php $id = $_GET['id']; // int $valor = $_GET['valor']; // float function processa(SplInt $id, SplFloat $valor) { echo $id, $valor; } processa(new SplInt($id), new SplFloat($valor));
  • 54. <?php $int = new SplInt('10'); // ?
  • 55. <?php $int = new SplInt('10'); // UnexpectedValueException: Value not an integer
  • 56. <?php $int = new SplInt('10', false); // Ok
  • 57. <?php $int = new SplInt('10'); if (!is_int('10')) throw new InvalidArgumentException('Tipo inválido'); $int1 = new SplInt('10', false); $int2 = '10'; if (!is_int($int2)) $int2 = (int) $int2;
  • 58. <?php $int = new SplInt(10); $int = 10; $int1 = new SplInt('10', false); $int1 = '10';
  • 59. <?php $int = new SplInt(10); $float = new SplFloat(10.7); echo $float + $int; echo $float - $int; echo $float / $int; echo $float * $int;
  • 60. <?php $id = $_GET['id']; // int $valor = $_GET['valor']; // float function processa(SplInt $id, SplFloat $valor) { echo $id, $valor; } processa($id, $valor); // Catchable fatal error: Argument 1 passed to processa() must be an instance of SplInt // Catchable fatal error: Argument 2 passed to processa() must be an instance of SplFloat
  • 61. <?php class Month extends SplEnum { const __default = self::January; const January = 1; const February = 2; const March = 3; const April = 4; const May = 5; const June = 6; const July = 7; const August = 8; const September = 9; const October = 10; const November = 11; const December = 12; }
  • 62. <?php class Month extends SplEnum { const __default = self::January; const January = 1; const February = 2; const March = 3; const April = 4; const May = 5; const June = 6; const July = 7; const August = 8; const September = 9; const October = 10; const November = 11; const December = 12; } function getMonth(Month $month) { echo $month; } getMonth(new Month(Month::October));
  • 63. <?php class Month extends SplEnum { const __default = self::January; const January = 1; const February = 2; const March = 3; const April = 4; const May = 5; const June = 6; const July = 7; const August = 8; const September = 9; const October = 10; const November = 11; const December = 12; } function getMonth(Month $month) { echo $month; } getMonth(new Month(13)); // UnexpectedValueException: Value not a const in enum Month
  • 64. <?php class Month extends SplEnum { const __default = self::January; const January = 1; const February = 2; const March = 3; const April = 4; const May = 5; const June = 6; const July = 7; const August = 8; const September = 9; const October = 10; const November = 11; const December = 12; } $month = new Month(); var_dump($month->getConstList());
  • 67. <?php function testInt(integer $value) { var_dump($value); } testInt(1);
  • 71. <?php function testInt(integer $value) { var_dump($value); } testInt('PHPubSP'); // Catchable fatal error: Argument 1 passed to testInt() must be of the type integer, string given
  • 72. <?php function testNumeric(numeric $value) { var_dump($value); } testNumeric('10');
  • 73. <?php function testCast((int) $value) { var_dump($value); } testCast('10');
  • 74. <?php function testScalar(scalar $value) { var_dump($value); } testScalar('10');
  • 75. <?php function testBool(bool $value) { // ... } function testString(string $value) { // ... } function testFloat(float $value) { // ... }