SlideShare uma empresa Scribd logo
1 de 57
Baixar para ler offline
Não é feitiçaria, é tecnologia.
    Metaprogramação com PHP




          Adler Medrado
     PHP Conference Brasil 2012

Monday, December 3, 12
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
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
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
Exemplos de
                             metadados
                   • XML
                   • Bancos de dados
                   • Anotações
                   • docComment
                   • YAML
                   • O próprio código, porque não?
Monday, December 3, 12
Como podem ser
                            usados ?
                   • WSDL
                   • .svn, .git, etc.
                   • Arquivos de configuração
                   • Dicionários de dados

Monday, December 3, 12
O que é
                         metaprogramação ?
               Alguns acham que é coisa de programador nerd
                                level hard




Monday, December 3, 12
Ou feitiçaria, magia negra,
                              coisas assim...




Monday, December 3, 12
MAS NÃO É




Monday, December 3, 12
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
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
Metaprogramação +
                                PHP
                   • A maioria dos frameworks PHP atuais
                         utilizam recursos de metaprogramação em
                         algum ponto;




Monday, December 3, 12
Metaprogramação +
                                PHP

                   • A propósito, eu arrisco dizer que você
                         também usa ou já usou tais recursos;




Monday, December 3, 12
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
__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
__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
__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
OK, isso não é
                 metaprogramação, mas...
                          Demonstra que o
                           PHP é flexível
                         Flexibilidade é ponto
                         chave em quase tudo

Monday, December 3, 12
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
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 true




Monday, December 3, 12
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.php


Monday, December 3, 12
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
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
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
Reflection API
                                 ReflectionClass -Invocando métodos


                   $r = new ReflectionClass('App');
                   echo $r->getMethod('getVersion')->invoke(new App());




Monday, December 3, 12
Reflection API
                                    ReflectionObject- Invocando métodos




                         $app = new App();
                         $r = new ReflectionObject($app);
                         echo $r->getMethod('getVersion')->invoke($app);




Monday, December 3, 12
Quer ver um exemplo melhor?




Monday, December 3, 12
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
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
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
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
Formulário gerado




Monday, December 3, 12
HTML gerado




Monday, December 3, 12
Annotations
                   •     Injeção de comportamento;
                   •     Desacoplamento;
                   •     Aonde costuma ser usado?
                         •   ORMs;
                         •   Dependency Injection Container;




Monday, December 3, 12
Annotations



                   • Não é um recurso nativo do PHP;
                   • Existem bibliotecas que fazem o trabalho
                         sujo;
                            https://wiki.php.net/rfc/annotations
Monday, December 3, 12
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
Annotations
                   • Quem usa annotations no mundo PHP ?
                    • Doctrine;
                    • Symfony;
                    • Flow3 Framework;
                    • PHPUnit;


Monday, December 3, 12
Annotations
       • Bibliotecas que implementam annotations
        • Doctrine/Common (packagist/composer);
        • php-annotations (https://github.com/mindplay-dk/
                    php-annotations




Monday, December 3, 12
Annotations
                   • Lembra do gerador de formulário?
                   • Que tal adicionarmos annotations a ele?




Monday, December 3, 12
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
ReflectionForm.php




                         <?php
                         abstract class ReflectionForm {

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




Monday, December 3, 12
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
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
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
Formulário gerado




                         Mesmo resultado que o exemplo anterior




Monday, December 3, 12
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:   9



Monday, December 3, 12
Lidando com objeto

        • Anteriormente, adicionamos
               propriedades a um objeto;
        • Que tal adicionarmos um
               método?




Monday, December 3, 12
Antes, uma pergunta:

                               Você já usou lambda
                               functions com PHP?



Monday, December 3, 12
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
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
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
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
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
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 trait

Monday, December 3, 12
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
Perguntas?


Monday, December 3, 12
Obrigado, até a próxima.
                         http://adlermedrado.com.br
                          http://getoncode.com.br
                              @adlermedrado



Monday, December 3, 12

Mais conteúdo relacionado

Destaque

Phpreact flisol-fb-2014
Phpreact flisol-fb-2014Phpreact flisol-fb-2014
Phpreact flisol-fb-2014Adler Medrado
 
Entendendo Conceitos Caching com PHP
Entendendo Conceitos Caching com PHPEntendendo Conceitos Caching com PHP
Entendendo Conceitos Caching com PHPAdler Medrado
 
Web 2.0 e RIA com PHP
Web 2.0 e RIA com PHPWeb 2.0 e RIA com PHP
Web 2.0 e RIA com PHPAdler Medrado
 
Mini Curso Zend Framework
Mini Curso Zend FrameworkMini Curso Zend Framework
Mini Curso Zend FrameworkAdler Medrado
 
Minicurso de PHP Com Ajax
Minicurso de PHP Com AjaxMinicurso de PHP Com Ajax
Minicurso de PHP Com AjaxAdler Medrado
 
Panorama atual do PHP
Panorama atual do PHPPanorama atual do PHP
Panorama atual do PHPAdler Medrado
 
Ferramentas Livres Para Desenvolvimento com PHP
Ferramentas Livres Para Desenvolvimento com PHPFerramentas Livres Para Desenvolvimento com PHP
Ferramentas Livres Para Desenvolvimento com PHPAdler Medrado
 
Esqueça a linguagem e vire um programador de verdade
Esqueça a linguagem e vire um programador de verdadeEsqueça a linguagem e vire um programador de verdade
Esqueça a linguagem e vire um programador de verdadePedro Chaves
 

Destaque (11)

Phpreact flisol-fb-2014
Phpreact flisol-fb-2014Phpreact flisol-fb-2014
Phpreact flisol-fb-2014
 
Entendendo Conceitos Caching com PHP
Entendendo Conceitos Caching com PHPEntendendo Conceitos Caching com PHP
Entendendo Conceitos Caching com PHP
 
Web 2.0 e RIA com PHP
Web 2.0 e RIA com PHPWeb 2.0 e RIA com PHP
Web 2.0 e RIA com PHP
 
Mini Curso Zend Framework
Mini Curso Zend FrameworkMini Curso Zend Framework
Mini Curso Zend Framework
 
Zend Framework
Zend FrameworkZend Framework
Zend Framework
 
Minicurso de PHP Com Ajax
Minicurso de PHP Com AjaxMinicurso de PHP Com Ajax
Minicurso de PHP Com Ajax
 
Zend Framework
Zend FrameworkZend Framework
Zend Framework
 
Panorama atual do PHP
Panorama atual do PHPPanorama atual do PHP
Panorama atual do PHP
 
Ferramentas Livres Para Desenvolvimento com PHP
Ferramentas Livres Para Desenvolvimento com PHPFerramentas Livres Para Desenvolvimento com PHP
Ferramentas Livres Para Desenvolvimento com PHP
 
Mercado de Trabalho
Mercado de TrabalhoMercado de Trabalho
Mercado de Trabalho
 
Esqueça a linguagem e vire um programador de verdade
Esqueça a linguagem e vire um programador de verdadeEsqueça a linguagem e vire um programador de verdade
Esqueça a linguagem e vire um programador de verdade
 

Semelhante a Não é Feitiçaria, é Tecnologia

PHP 5.3 - Classes e Objetos
PHP 5.3 - Classes e ObjetosPHP 5.3 - Classes e Objetos
PHP 5.3 - Classes e ObjetosGeorge Mendonça
 
Conhecendo Ruby on Rails
Conhecendo Ruby on RailsConhecendo Ruby on Rails
Conhecendo Ruby on RailsSergio Henrique
 
Entendendo o OpenLDAP - GABRIEL STEIN
Entendendo o OpenLDAP - GABRIEL STEINEntendendo o OpenLDAP - GABRIEL STEIN
Entendendo o OpenLDAP - GABRIEL STEINTchelinux
 
Perl Moderno, dia5
Perl Moderno, dia5Perl Moderno, dia5
Perl Moderno, dia5garux
 
Abstração do banco de dados com PHP Doctrine
Abstração do banco de dados com PHP DoctrineAbstração do banco de dados com PHP Doctrine
Abstração do banco de dados com PHP DoctrineOtávio Calaça Xavier
 
Php5 e a orientação a objetos
Php5 e a orientação a objetosPhp5 e a orientação a objetos
Php5 e a orientação a objetosxbacon
 
(Re)pensando a OOP - TDC 2012
(Re)pensando a OOP - TDC 2012(Re)pensando a OOP - TDC 2012
(Re)pensando a OOP - TDC 2012Luís Cobucci
 
Refatoração - aquela caprichada no código
Refatoração - aquela caprichada no códigoRefatoração - aquela caprichada no código
Refatoração - aquela caprichada no códigoJuciellen Cabrera
 
(Re)pensando a OOP - Flisol Gyn
(Re)pensando a OOP - Flisol Gyn(Re)pensando a OOP - Flisol Gyn
(Re)pensando a OOP - Flisol GynLuís Cobucci
 
Uma Abordagem Prática de Orientação a Objetos com PHP (FLISOL DF 2011)
Uma Abordagem Prática de Orientação a Objetos com PHP (FLISOL DF 2011)Uma Abordagem Prática de Orientação a Objetos com PHP (FLISOL DF 2011)
Uma Abordagem Prática de Orientação a Objetos com PHP (FLISOL DF 2011)George Mendonça
 
Introdução a Linguagem de Programação Ruby
Introdução a Linguagem de Programação RubyIntrodução a Linguagem de Programação Ruby
Introdução a Linguagem de Programação RubyDiego Rubin
 

Semelhante a Não é Feitiçaria, é Tecnologia (20)

PHP 5.3 - Classes e Objetos
PHP 5.3 - Classes e ObjetosPHP 5.3 - Classes e Objetos
PHP 5.3 - Classes e Objetos
 
Migrando para o PHP 5
Migrando para o PHP 5Migrando para o PHP 5
Migrando para o PHP 5
 
Conhecendo Ruby on Rails
Conhecendo Ruby on RailsConhecendo Ruby on Rails
Conhecendo Ruby on Rails
 
Entendendo o OpenLDAP - GABRIEL STEIN
Entendendo o OpenLDAP - GABRIEL STEINEntendendo o OpenLDAP - GABRIEL STEIN
Entendendo o OpenLDAP - GABRIEL STEIN
 
Perl Moderno, dia5
Perl Moderno, dia5Perl Moderno, dia5
Perl Moderno, dia5
 
Abstração do banco de dados com PHP Doctrine
Abstração do banco de dados com PHP DoctrineAbstração do banco de dados com PHP Doctrine
Abstração do banco de dados com PHP Doctrine
 
Php5 e a orientação a objetos
Php5 e a orientação a objetosPhp5 e a orientação a objetos
Php5 e a orientação a objetos
 
Aula5
Aula5Aula5
Aula5
 
Groovy & grails
Groovy & grailsGroovy & grails
Groovy & grails
 
Groovy & Grails
Groovy & GrailsGroovy & Grails
Groovy & Grails
 
Aula4
Aula4Aula4
Aula4
 
Curso de PHP - Objetos
Curso de PHP - ObjetosCurso de PHP - Objetos
Curso de PHP - Objetos
 
PHP 5.3 - What's new?
PHP 5.3 - What's new?PHP 5.3 - What's new?
PHP 5.3 - What's new?
 
(Re)pensando a OOP - TDC 2012
(Re)pensando a OOP - TDC 2012(Re)pensando a OOP - TDC 2012
(Re)pensando a OOP - TDC 2012
 
Refatoração - aquela caprichada no código
Refatoração - aquela caprichada no códigoRefatoração - aquela caprichada no código
Refatoração - aquela caprichada no código
 
(Re)pensando a OOP - Flisol Gyn
(Re)pensando a OOP - Flisol Gyn(Re)pensando a OOP - Flisol Gyn
(Re)pensando a OOP - Flisol Gyn
 
Doctrine for dummies
Doctrine for dummiesDoctrine for dummies
Doctrine for dummies
 
Uma Abordagem Prática de Orientação a Objetos com PHP (FLISOL DF 2011)
Uma Abordagem Prática de Orientação a Objetos com PHP (FLISOL DF 2011)Uma Abordagem Prática de Orientação a Objetos com PHP (FLISOL DF 2011)
Uma Abordagem Prática de Orientação a Objetos com PHP (FLISOL DF 2011)
 
Refactoring
RefactoringRefactoring
Refactoring
 
Introdução a Linguagem de Programação Ruby
Introdução a Linguagem de Programação RubyIntrodução a Linguagem de Programação Ruby
Introdução a Linguagem de Programação Ruby
 

Não é Feitiçaria, é Tecnologia

  • 1. Não é feitiçaria, é tecnologia. Metaprogramação com PHP Adler Medrado PHP Conference Brasil 2012 Monday, December 3, 12
  • 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. 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. 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. Exemplos de metadados • XML • Bancos de dados • Anotações • docComment • YAML • O próprio código, porque não? Monday, December 3, 12
  • 6. Como podem ser usados ? • WSDL • .svn, .git, etc. • Arquivos de configuração • Dicionários de dados Monday, December 3, 12
  • 7. O que é metaprogramação ? Alguns acham que é coisa de programador nerd level hard Monday, December 3, 12
  • 8. Ou feitiçaria, magia negra, coisas assim... Monday, December 3, 12
  • 9. MAS NÃO É Monday, December 3, 12
  • 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. 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. Metaprogramação + PHP • A maioria dos frameworks PHP atuais utilizam recursos de metaprogramação em algum ponto; Monday, December 3, 12
  • 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. 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. __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. __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. __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. OK, isso não é metaprogramação, mas... Demonstra que o PHP é flexível Flexibilidade é ponto chave em quase tudo Monday, December 3, 12
  • 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. 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 true Monday, December 3, 12
  • 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.php Monday, December 3, 12
  • 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. 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. 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. Reflection API ReflectionClass -Invocando métodos $r = new ReflectionClass('App'); echo $r->getMethod('getVersion')->invoke(new App()); Monday, December 3, 12
  • 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. Quer ver um exemplo melhor? Monday, December 3, 12
  • 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. 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. 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. 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
  • 34. Annotations • Injeção de comportamento; • Desacoplamento; • Aonde costuma ser usado? • ORMs; • Dependency Injection Container; Monday, December 3, 12
  • 35. Annotations • Não é um recurso nativo do PHP; • Existem bibliotecas que fazem o trabalho sujo; https://wiki.php.net/rfc/annotations Monday, December 3, 12
  • 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. Annotations • Quem usa annotations no mundo PHP ? • Doctrine; • Symfony; • Flow3 Framework; • PHPUnit; Monday, December 3, 12
  • 38. Annotations • Bibliotecas que implementam annotations • Doctrine/Common (packagist/composer); • php-annotations (https://github.com/mindplay-dk/ php-annotations Monday, December 3, 12
  • 39. Annotations • Lembra do gerador de formulário? • Que tal adicionarmos annotations a ele? Monday, December 3, 12
  • 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. ReflectionForm.php <?php abstract class ReflectionForm { private $metadataFields; public function __construct() { $this->metadataFields = array(); } Monday, December 3, 12
  • 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. 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. 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. Formulário gerado Mesmo resultado que o exemplo anterior Monday, December 3, 12
  • 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: 9 Monday, December 3, 12
  • 47. Lidando com objeto • Anteriormente, adicionamos propriedades a um objeto; • Que tal adicionarmos um método? Monday, December 3, 12
  • 48. Antes, uma pergunta: Você já usou lambda functions com PHP? Monday, December 3, 12
  • 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. 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. 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. 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. 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. 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 trait Monday, December 3, 12
  • 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
  • 57. Obrigado, até a próxima. http://adlermedrado.com.br http://getoncode.com.br @adlermedrado Monday, December 3, 12