Não é Feitiçaria, é Tecnologia

2,000 views
1,810 views

Published on

Metaprogramação com PHP

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,000
On SlideShare
0
From Embeds
0
Number of Embeds
117
Actions
Shares
0
Downloads
12
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Não é Feitiçaria, é Tecnologia

  1. 1. Não é feitiçaria, é tecnologia. Metaprogramação com PHP Adler Medrado PHP Conference Brasil 2012Monday, December 3, 12
  2. 2. Quem sou eu ? • Desenvolvedor, Consultor, Instrutor; • Trabalha na Sigma Dataserv; • Co-Fundador do PHPDF; • Fui apresentado ao PHP em 1999; • Tenho meu próprio podcast (getOnCode); • ZCE • PHP 5; • Zend Framework;Monday, December 3, 12
  3. 3. Meta • Do grego, μετά • após, além, adjacente Indica o conceito de abstração de outro conceito, que completa e adiciona a este último.Monday, December 3, 12
  4. 4. Metadado (metadata) • Termo criado por Philip Bagley em 1986, na obra “Extension of Programming Language Concepts”; • Dados sobre outros dados; • Informa, descreve sobre o dado em questão; • Serve como marco ou ponto de referência;Monday, December 3, 12
  5. 5. Exemplos de metadados • XML • Bancos de dados • Anotações • docComment • YAML • O próprio código, porque não?Monday, December 3, 12
  6. 6. Como podem ser usados ? • WSDL • .svn, .git, etc. • Arquivos de configuração • Dicionários de dadosMonday, December 3, 12
  7. 7. O que é metaprogramação ? Alguns acham que é coisa de programador nerd level hardMonday, December 3, 12
  8. 8. Ou feitiçaria, magia negra, coisas assim...Monday, December 3, 12
  9. 9. MAS NÃO ÉMonday, December 3, 12
  10. 10. O que é metaprogramação ? • Fornece a capacidade de gerar ou alterar o comportamento de um programa em tempo de execução ou compilação baseado em metadados;Monday, December 3, 12
  11. 11. Metaprogramação + PHP • O PHP não oferece tantos recursos como o Ruby para utilizar tal técnica; • Mas os recursos que já existiam somados a outros oferecidos com o advento do PHP 5.3 e 5.4 nos permite fazer coisas interessantes;Monday, December 3, 12
  12. 12. Metaprogramação + PHP • A maioria dos frameworks PHP atuais utilizam recursos de metaprogramação em algum ponto;Monday, December 3, 12
  13. 13. Metaprogramação + PHP • A propósito, eu arrisco dizer que você também usa ou já usou tais recursos;Monday, December 3, 12
  14. 14. Metaprogramação + PHP • Você conhece os métodos mágicos do PHP? • Eles podem ser usados para alterar o comportamento do objeto;Monday, December 3, 12
  15. 15. __get() class Examples { private $property; public function __construct() { $this->property = Esse é um exemplo; } public function __get($property) { return $this->$property; } } $e = new Examples; echo $e->property;Monday, December 3, 12
  16. 16. __set($prop, $val) class Examples { private $property; public function __construct() { $this->property = Esse é um exemplo; } public function __get($property) { return $this->$property; } public function __set($property, $value) { $this->$property = $value; } } $e = new Examples; echo $e->property; $e->property = <br />mudei o valor<br />; echo $e->property;Monday, December 3, 12
  17. 17. __call($name, $params) <?php class Exemplos { private $property; public function __construct() { $this->property = Esse é um exemplo; } public function __call($name, $args) { echo invocando o método . $name . com os argumentos . join(, , $args); } } $e = new Exemplos; $e->umMetodoQualquer(param1, param2, param3);Monday, December 3, 12
  18. 18. OK, isso não é metaprogramação, mas... Demonstra que o PHP é flexível Flexibilidade é ponto chave em quase tudoMonday, December 3, 12
  19. 19. Falando em flexibilidade ... Que tal adicionarmos propriedades em tempo de execução? <?php class Person { } $adler = new Person; var_dump($adler); object(Person)[1] Não existem propriedades neste objeto.Monday, December 3, 12
  20. 20. Falando em flexibilidade ... <?php class Person { } $adler = new Person; $adler->nome = Adler Medrado; $adler->bonitao = true; var_dump($adler); ?> object(Person)[1] public nome => string Adler Medrado (length=13) public bonitao => boolean trueMonday, December 3, 12
  21. 21. Reflection API • Desde a primeira release do PHP 5; • Introspecção; • Engenharia-Reversa; • Acesso a metadados (PHPDoc); • http://www.php.net/manual/en/ book.reflection.phpMonday, December 3, 12
  22. 22. Reflection API • Possíveis usos no mundo real; • Geração de WSDL; • Geração de formulários; • Uso de anotações em PHP; • Entre outros . . . • Zend_XmlRpc usa Reflection;Monday, December 3, 12
  23. 23. Reflection API Imagine a seguinte classe <?php class App { private $name; private $version; public function __construct() { $this->name = Exemplo; $this->version = 1.0; } public function getVersion() { return $this->version; } }Monday, December 3, 12
  24. 24. Reflection API echo <pre>; ReflectionClass::export(App); echo </pre>; Class [ class App ] { @@ /Users/adler/Dropbox/palestras-phpconference-2012/metaprogramacao/reflection/sample_class.php 2-14 - Constants [0] { } - Static properties [0] { } - Static methods [0] { } - Properties [2] { Property [ private $name ] Property [ private $version ] } - Methods [2] { Method [ public method __construct ] { @@ /Users/adler/Dropbox/palestras-phpconference-2012/metaprogramacao/reflection/sample_class.php 6 - 9 } Method [ public method getVersion ] { @@ /Users/adler/Dropbox/palestras-phpconference-2012/metaprogramacao/reflection/sample_class.php 11 - 13 } } }Monday, December 3, 12
  25. 25. Reflection API ReflectionClass -Invocando métodos $r = new ReflectionClass(App); echo $r->getMethod(getVersion)->invoke(new App());Monday, December 3, 12
  26. 26. Reflection API ReflectionObject- Invocando métodos $app = new App(); $r = new ReflectionObject($app); echo $r->getMethod(getVersion)->invoke($app);Monday, December 3, 12
  27. 27. Quer ver um exemplo melhor?Monday, December 3, 12
  28. 28. Um simples gerador de formulários • Consiste em um gerador de formulário HTML baseado em um objeto PHP; • Pode ser incrementado posteriormente implementando filtros, validações, etc.;Monday, December 3, 12
  29. 29. Empresa.php <?php require ReflectionForm.php; class Empresa extends ReflectionForm { private $nome; private $razao_social; private $endereco; private $bairro; private $cidade; private $estado; private $telefone; private $email; }Monday, December 3, 12
  30. 30. ReflectionForm.php <?php abstract class ReflectionForm { private $generated; public function parse() { Obtém o objeto de Reflexão $r = new ReflectionObject($this); Obtém as propriedades $fields = $r->getProperties(); array_walk($fields, function($field) { $this->generated .= "<div>" . ucfirst($field->getName()) . "</div>n"; $this->generated .= "<div><input type="text" name="" . $field->getName() . "" /></div>n"; }); return $this->generated; } }Monday, December 3, 12
  31. 31. exemplo.php <?php require Empresa.php; $empresa = new Empresa(); ?> <html> <head> <title>Exemplo - Form Generator</title> </head> <body id="formGenerator"> <form action="" method="post" accept- charset="utf-8"> <?=$empresa->parse(); ?> </form> </body> </html>Monday, December 3, 12
  32. 32. Formulário geradoMonday, December 3, 12
  33. 33. HTML geradoMonday, December 3, 12
  34. 34. Annotations • Injeção de comportamento; • Desacoplamento; • Aonde costuma ser usado? • ORMs; • Dependency Injection Container;Monday, December 3, 12
  35. 35. Annotations • Não é um recurso nativo do PHP; • Existem bibliotecas que fazem o trabalho sujo; https://wiki.php.net/rfc/annotationsMonday, December 3, 12
  36. 36. Annotations • Por essência, annotation é metaprogramação; • No PHP, annotation é uma simulação feita usando a sintaxe PHPDoc + Reflection; • Metaprogramação para implementar um recurso de Metalinguagem;Monday, December 3, 12
  37. 37. Annotations • Quem usa annotations no mundo PHP ? • Doctrine; • Symfony; • Flow3 Framework; • PHPUnit;Monday, December 3, 12
  38. 38. Annotations • Bibliotecas que implementam annotations • Doctrine/Common (packagist/composer); • php-annotations (https://github.com/mindplay-dk/ php-annotationsMonday, December 3, 12
  39. 39. Annotations • Lembra do gerador de formulário? • Que tal adicionarmos annotations a ele?Monday, December 3, 12
  40. 40. Empresa.php <?php require ReflectionForm.php; class Empresa extends ReflectionForm { /** * @var string * @type text */ private $nome; /** * @var string * @type text */ private $razao_social; /** * @var string * @type text */ private $endereco; // Demais propriedades... }Monday, December 3, 12
  41. 41. ReflectionForm.php <?php abstract class ReflectionForm { private $metadataFields; public function __construct() { $this->metadataFields = array(); } Monday, December 3, 12
  42. 42. ReflectionForm.php (Continuação) public function parse() { $this->getFormInfo(); $generated = ; foreach($this->metadataFields as $fieldName => $fieldParams) { $generated .= "<div>" . ucfirst($fieldName) . "</div>n"; $generated .= "<div><input type="" $generated .= $fieldParams[type] . "" name="" $generated .=. $fieldName . "" /></div>n"; } return $generated; }Monday, December 3, 12
  43. 43. ReflectionForm.php (Continuação) private function getFormInfo() { $r = new ReflectionObject($this); $fields = $r->getProperties(); array_walk($fields, function($field) { $lines = array(); $doc = $field->getDocComment(); if (preg_match(#^/**(.*)*/#s, $doc, $comment) === false) throw new Exception(Error getting comment); $params = trim($comment[1]); if(preg_match_all(#^s**(.*)#m, $params, $lines) === false) throw new Exception(Error getting lines); foreach($lines[1] as $line) { $this->getVariables($field->getName(), $line); } }); }Monday, December 3, 12
  44. 44. ReflectionForm.php (Continuação) private function getVariables($fieldName, $line) { $line = trim($line); if(empty($line)) return false; if(strpos($line, @) === 0) { $param = substr($line, 1, strpos($line, ) - 1); $value = substr($line, strlen($param) + 2); $this->metadataFields[$fieldName] = array($param => $value); } }Monday, December 3, 12
  45. 45. Formulário gerado Mesmo resultado que o exemplo anteriorMonday, December 3, 12
  46. 46. Geração de Código Prazer, meu nome é eval() <?php $codigo = for ($i = 0; $i < 10; $i++) {; $codigo .= echo Contando: . $i . <br />;; $codigo .= }; eval($codigo); Contando: 0 Contando: 1 Contando: 2 Contando: 3 Contando: 4 Contando: 5 Contando: 6 Contando: 7 Contando: 8 Contando: 9Monday, December 3, 12
  47. 47. Lidando com objeto • Anteriormente, adicionamos propriedades a um objeto; • Que tal adicionarmos um método?Monday, December 3, 12
  48. 48. Antes, uma pergunta: Você já usou lambda functions com PHP?Monday, December 3, 12
  49. 49. De acordo com a documentação oficial: Anonymous functions, also known as closures, allow the creation of functions which have no specified name. They are most useful as the value of callback parameters, but they have many other uses. <?php $silvio = function() { return "maaa oeeeee"; }; echo $silvio();Monday, December 3, 12
  50. 50. Criamos uma classe... <?php class Carro { private $modelo, $ano, functionArgs; public function __construct($modelo, $ano) { $this -> modelo = $modelo; $this -> ano = $ano; } public function ligar() { echo "Ligando o carron"; } public function __call($method, $args) { if ($this->{$method} instanceof Closure) { return call_user_func_array($this->{$method}, $args); } } }Monday, December 3, 12
  51. 51. e adicionamos um método <?php require Carro.php; $carro = new Carro(Uno,1995); $carro->ligar(); $str = $carro->buzinar = function() {; $str .= "echo "fom fom n";"; $str .= "};"; eval($str); $carro->buzinar(); ?>Monday, December 3, 12
  52. 52. Vamos adicionar um método nessa classe? public function createNewMethod($name, $args, $code) { if ((!is_null($args)) && (sizeof($args) == 0)) { array_walk($args, function($value) { if (empty($this->functionArgs)) { $this->functionArgs .= $ . $value; } else { $this->functionArgs .= ,$ . $value; } }); } $functionDefinition = $this->{$name} = function (. $this->functionArgs. ); $functionDefinition .= {.$code.};; eval($functionDefinition); $this->functionArgs = null; }Monday, December 3, 12
  53. 53. Adicionando método... <?php require Carro.php; $carro = new Carro(Uno,1995); $carro->ligar(); $carro->createNewMethod(buzinar, null, return "biii biin";); echo $carro->buzinar();Monday, December 3, 12
  54. 54. Que tal deixar a classe <?php mais limpa? trait genMetodo { private $functionArgs; public function createNewMethod($name, $args, $code) { if ((!is_null($args)) && (sizeof($args) == 0)) { array_walk($args, function($value) { if (empty($this->functionArgs)) { $this->functionArgs .= $ . $value; } else { $this->functionArgs .= ,$ . $value; } }); } $functionDefinition = $this->{$name} = function (. $this->functionArgs. ); $functionDefinition .= {.$code.};; eval($functionDefinition); $this->functionArgs = null; } Obs: O método __call também pode ser definido na traitMonday, December 3, 12
  55. 55. Que tal deixar a classe mais limpa? <?php class Carro { use genMetodo; private $modelo, $ano, $functionArgs; public function __construct($modelo, $ano) { $this->modelo = $modelo; $this->ano = $ano; $this->functionArgs = null; } public function ligar() { echo "Ligando o carron"; } public function __call($method, $args) { if ($this -> {$method} instanceof Closure) { return call_user_func_array($this -> {$method}, $args); } } }Monday, December 3, 12
  56. 56. Perguntas?Monday, December 3, 12
  57. 57. Obrigado, até a próxima. http://adlermedrado.com.br http://getoncode.com.br @adlermedradoMonday, December 3, 12

×