Anúncio

PHP ao Extremo

Software Developer em Emprego Ligado
19 de Dec de 2011
Anúncio

Mais conteúdo relacionado

Anúncio

Último(20)

PHP ao Extremo

  1. 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);
  10. Sobrecarga de operador
  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));
  17. Exemplo do mundo real
  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
  21. Injeção de Dependência
  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;
  26. Inversão de Controle
  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; } }
  30. runkit https://github.com/zenovich/runkit/
  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)
  44. Variáveis Tipadas
  45. PHP tem tipo???
  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());
  65. Scalar Type Hinting
  66. <?php function foo(array $value) { // ... }
  67. <?php function testInt(integer $value) { var_dump($value); } testInt(1);
  68. http://svn.php.net/viewvc? view=revision&revision=299534
  69. https://svn.php.net/repository/php/php-src/ branches/WITH_SCALAR_TYPES/
  70. http://ilia.ws/archives/207-Type-Hinting- Conclusion.html
  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) { // ... }
  76. Perguntas???
Anúncio