SlideShare una empresa de Scribd logo
1 de 76
Descargar para leer sin conexión
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???

Más contenido relacionado

La actualidad más candente

Programando em python dicionarios
Programando em python   dicionariosProgramando em python   dicionarios
Programando em python dicionarios
samuelthiago
 
LabMM4 (T13 - 12/13) - Funções
LabMM4 (T13 - 12/13) - FunçõesLabMM4 (T13 - 12/13) - Funções
LabMM4 (T13 - 12/13) - Funções
Carlos Santos
 
Criando APIs usando o micro-framework Respect
Criando APIs usando o micro-framework RespectCriando APIs usando o micro-framework Respect
Criando APIs usando o micro-framework Respect
Ivan Rosolen
 
Criando controle de acesso com php e my sql
Criando controle de acesso com php e my sqlCriando controle de acesso com php e my sql
Criando controle de acesso com php e my sql
Paulo Damas
 

La actualidad más candente (20)

Introdução ao Respect\Validation (1.0)
Introdução ao Respect\Validation (1.0)Introdução ao Respect\Validation (1.0)
Introdução ao Respect\Validation (1.0)
 
Palestra Novidades da linguagem C# 6
Palestra Novidades da linguagem C# 6Palestra Novidades da linguagem C# 6
Palestra Novidades da linguagem C# 6
 
Programando em python dicionarios
Programando em python   dicionariosProgramando em python   dicionarios
Programando em python dicionarios
 
modernizando a arquitertura de sua aplicação
modernizando a arquitertura  de sua aplicaçãomodernizando a arquitertura  de sua aplicação
modernizando a arquitertura de sua aplicação
 
Da Argila Ao Forte - Como desenvolver uma loja virtual
Da Argila Ao Forte - Como desenvolver uma loja virtualDa Argila Ao Forte - Como desenvolver uma loja virtual
Da Argila Ao Forte - Como desenvolver uma loja virtual
 
Minicurso de jQuery
Minicurso de jQueryMinicurso de jQuery
Minicurso de jQuery
 
LabMM4 (T13 - 12/13) - Funções
LabMM4 (T13 - 12/13) - FunçõesLabMM4 (T13 - 12/13) - Funções
LabMM4 (T13 - 12/13) - Funções
 
Clean code
Clean codeClean code
Clean code
 
Criando APIs usando o micro-framework Respect
Criando APIs usando o micro-framework RespectCriando APIs usando o micro-framework Respect
Criando APIs usando o micro-framework Respect
 
SPL Datastructures
SPL DatastructuresSPL Datastructures
SPL Datastructures
 
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
 
Introdução ao MongoDB
Introdução ao MongoDBIntrodução ao MongoDB
Introdução ao MongoDB
 
Java 8 - Afinal onde usamos no dia a dia? TDC 2015 - Porto Alegre
Java 8 - Afinal onde usamos no dia a dia? TDC 2015 - Porto AlegreJava 8 - Afinal onde usamos no dia a dia? TDC 2015 - Porto Alegre
Java 8 - Afinal onde usamos no dia a dia? TDC 2015 - Porto Alegre
 
Hooks, o condimento mágico e escondido do WordPress
Hooks, o condimento mágico e escondido do WordPressHooks, o condimento mágico e escondido do WordPress
Hooks, o condimento mágico e escondido do WordPress
 
Java script - funções
Java script - funçõesJava script - funções
Java script - funções
 
Escrevendo plugins JQuery
Escrevendo plugins JQueryEscrevendo plugins JQuery
Escrevendo plugins JQuery
 
Spring Capitulo 03
Spring Capitulo 03Spring Capitulo 03
Spring Capitulo 03
 
Criando controle de acesso com php e my sql
Criando controle de acesso com php e my sqlCriando controle de acesso com php e my sql
Criando controle de acesso com php e my sql
 
Refactoring sem complicação!
Refactoring sem complicação!Refactoring sem complicação!
Refactoring sem complicação!
 
Orientação a Objetos em PHP
Orientação a Objetos em PHPOrientação a Objetos em PHP
Orientação a Objetos em PHP
 

Similar a PHP ao Extremo

Ecommerce, mais simples do que parece
Ecommerce, mais simples do que pareceEcommerce, mais simples do que parece
Ecommerce, mais simples do que parece
Impacta Eventos
 
As novidades do PHP5 (2005)
As novidades do PHP5 (2005)As novidades do PHP5 (2005)
As novidades do PHP5 (2005)
Pablo Dall'Oglio
 
Aula 12 Relatório - Tabelas
Aula 12   Relatório - TabelasAula 12   Relatório - Tabelas
Aula 12 Relatório - Tabelas
Dalton Martins
 
PHP: Linguagem + Mysql + MVC + AJAX
PHP: Linguagem + Mysql + MVC + AJAX PHP: Linguagem + Mysql + MVC + AJAX
PHP: Linguagem + Mysql + MVC + AJAX
Sérgio Souza Costa
 

Similar a PHP ao Extremo (20)

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

Último

Assessement Boas Praticas em Kubernetes.pdf
Assessement Boas Praticas em Kubernetes.pdfAssessement Boas Praticas em Kubernetes.pdf
Assessement Boas Praticas em Kubernetes.pdf
Natalia Granato
 

Último (6)

Padrões de Projeto: Proxy e Command com exemplo
Padrões de Projeto: Proxy e Command com exemploPadrões de Projeto: Proxy e Command com exemplo
Padrões de Projeto: Proxy e Command com exemplo
 
ATIVIDADE 1 - CUSTOS DE PRODUÇÃO - 52_2024.docx
ATIVIDADE 1 - CUSTOS DE PRODUÇÃO - 52_2024.docxATIVIDADE 1 - CUSTOS DE PRODUÇÃO - 52_2024.docx
ATIVIDADE 1 - CUSTOS DE PRODUÇÃO - 52_2024.docx
 
ATIVIDADE 1 - LOGÍSTICA EMPRESARIAL - 52_2024.docx
ATIVIDADE 1 - LOGÍSTICA EMPRESARIAL - 52_2024.docxATIVIDADE 1 - LOGÍSTICA EMPRESARIAL - 52_2024.docx
ATIVIDADE 1 - LOGÍSTICA EMPRESARIAL - 52_2024.docx
 
ATIVIDADE 1 - GCOM - GESTÃO DA INFORMAÇÃO - 54_2024.docx
ATIVIDADE 1 - GCOM - GESTÃO DA INFORMAÇÃO - 54_2024.docxATIVIDADE 1 - GCOM - GESTÃO DA INFORMAÇÃO - 54_2024.docx
ATIVIDADE 1 - GCOM - GESTÃO DA INFORMAÇÃO - 54_2024.docx
 
Assessement Boas Praticas em Kubernetes.pdf
Assessement Boas Praticas em Kubernetes.pdfAssessement Boas Praticas em Kubernetes.pdf
Assessement Boas Praticas em Kubernetes.pdf
 
Boas práticas de programação com Object Calisthenics
Boas práticas de programação com Object CalisthenicsBoas práticas de programação com Object Calisthenics
Boas práticas de programação com Object Calisthenics
 

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);
  • 69. https://svn.php.net/repository/php/php-src/ branches/WITH_SCALAR_TYPES/
  • 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) { // ... }