PHP, Programando com Orientação a Objetos [Parte 4]

PHP, Programando com Orientação a Objetos [Parte 4]
Tempo de leitura: 5 min de leitura
Link copiado!

Buenas PessoALL!

Continuando o post anterior PHP, Programando com Orientação a Objetos, Parte 3, apartir de agora passaremos a introdução de orientação a objetos.

2.4] Manipulação de Objetos

get_class_methods

Retorna um vetor com os nomes dos métodos de uma determinada classe.

<?php
class Funcionario
{
    function SetSalario()
    {
    }
    function GetSalario()
    {
    }
    function SetNome()
    {
    }
    function GetNome()
    {
    }
}
print_r(get_class_methods('Funcionario'));

/*
Resultado:
Array
(
    [0] => SetSalario
    [1] => GetSalario
    [2] => SetNome
    [3] => GetNome
)
*/
?>

get_class_vars

Retorna um vetor com os nomes das propriedades e conteúdos de uma determinada classe. Note que são valores estáticos definidos na criação da classe.

<?php
class Funcionario
{
    var $Codigo;
    var $Nome;
    var $Salario = 586;
    var $Departamento = 'Contabilidade';
    
    function SetSalario()
    {
    }
    function GetSalario()
    {
    }
}
print_r(get_class_vars('Funcionario'));

/*
Resultado:
Array
(
    [Codigo] =>
    [Nome] =>
    [Salario] => 586
    [Departamento] => Contabilidade
)
*/
?>

get_object_vars

Retorna um vetor com os nomes e conteúdos das propriedades de um objeto. São valores dinâmicos que se alteram de acordo com o ciclo de vida do objeto.

<?php
class Funcionario
{
    var $Codigo;
    var $Nome;
    var $Salario = 586;
    var $Departamento = 'Contabilidade';
    
    function SetSalario()
    {
    }
    function GetSalario()
    {
    }
}

$jose = new Funcionario;
$jose->Codigo = 44;
$jose->Nome = 'José da Silva';
$jose->Salario += 100;
$jose->Departamento = 'Financeiro';
print_r(get_object_vars($jose));

/*
Resultado:
Array
(
    [Codigo] => 44
    [Nome] => José da Silva
    [Salario] => 686
    [Departamento] => Financeiro
)
*/
?>

get_class

Retorna o nome da classe à qual um objeto pertence.

<?php
class Funcionario
{
    var $Codigo;
    var $Nome;
    
    function SetSalario()
    {
    }
    function GetSalario()
    {
    }
}

$jose = new Funcionario;
echo get_class($jose);

/*
Resultado:
Funcionario
*/
?>

get_parent_class

Retorna o nome da classe ancestral (classe-pai). Se o parâmetro for um objeto, retorna o nome da classe ancestral da classe à qual o objeto pertence. Se o parâmetro for uma string, retorna o nome da classe ancestral da classe passada como parâmetro.

<?php
class Funcionario
{
    var $Codigo;
    var $Nome;
}

class Estagiario extends Funcionario
{
    var $Salario;
    var $Bolsa;
}

$jose = new Estagiario;
echo get_parent_class($jose);
echo "\n";    // quebra de linha
echo get_parent_class('estagiario');

/*
Resultado:
Funcionario
Funcionario
*/
?>

is_subclass_of

Indica se um determinado objeto ou classe é derivado de uma determinada classe.

<?php
class Funcionario
{
    var $Codigo;
    var $Nome;
}

class Estagiario extends Funcionario
{
    var $Salario;
    var $Bolsa;
}

$jose = new Estagiario;
if (is_subclass_of($jose, 'Funcionario'))
{
    echo "Classe do objeto Jose é derivada de Funcionario";
}
echo "\n";    // quebra de linha
if (is_subclass_of('Estagiario', 'Funcionario'))
{
    echo "Classe Estagiario é derivada de Funcionario";
}

/*
Resultado:
Classe do objeto Jose é derivada de Funcionario
Classe Estagiario é derivada de Funcionario
*/
?>

method_exists

Verifica se um determinado objeto possui o método descrito. Podemos verificar a existência de um método antes de executar por engano um método inexistente.

<?php
class Funcionario
{
    var $Codigo;
    var $Nome;
    
    function GetSalario()
    {
    }
    function SetSalario()
    {
    }
}

$jose = new Funcionario;
if (method_exists($jose, 'SetNome'))
{
    echo 'Objeto Jose possui método SetNome()';
}
if (method_exists($jose, 'SetSalario'))
{
    echo 'Objeto Jose possui método SetSalario()';
}

/*
Resultado:
Objeto Jose possui método SetSalario()
*/
?>

call_user_func

Executa uma função ou um método de uma classe passado como parâmetro. Para executar uma função, basta passar seu nome como uma string, e, para executar um método de um objeto, basta passar o parâmetro como um array contendo na posição 0 o objeto e na posição 1 o método a ser executado. Para executar métodos estáticos, basta passar o nome da classe em vez do objeto na posição 0 do array.

<?php
// exemplo chamada simples
function minhafuncao()
{
    echo "minha função! \n";
}
call_user_func('minhafuncao');

// declaração de classe
class MinhaClasse
{
    function MeuMetodo()
    {
        echo "Meu método! \n";
    }
}

// chamada de método estático
call_user_func(array('MinhaClasse', 'MeuMetodo'));

// chamada de método
$obj = new MinhaClasse();
call_user_func(array($obj, 'MeuMetodo'));

/*
Resultado:
minha função!
Meu método!
Meu método!
*/
?>

Funções Avançadas de Introspecção

class_exists

Verifica se uma classe foi definida:

<?php
if (class_exists('Funcionario')) {
    echo "Classe Funcionario existe";
} else {
    echo "Classe Funcionario não existe";
}
?>

interface_exists

Verifica se uma interface foi definida:

<?php
interface MinhaInterface
{
    public function metodoObrigatorio();
}

if (interface_exists('MinhaInterface')) {
    echo "Interface MinhaInterface existe";
}
?>

property_exists

Verifica se uma propriedade existe em uma classe ou objeto:

<?php
class Funcionario
{
    public $nome;
    private $salario;
}

$funcionario = new Funcionario();

var_dump(property_exists('Funcionario', 'nome'));     // true
var_dump(property_exists($funcionario, 'salario'));  // true
var_dump(property_exists('Funcionario', 'idade'));   // false
?>

Reflexão em PHP

A reflexão permite examinar classes, métodos e propriedades em tempo de execução.

ReflectionClass

<?php
class Usuario
{
    public $nome;
    private $senha;
    
    public function login($usuario, $senha)
    {
        // lógica do login
    }
    
    private function criptografar($texto)
    {
        // lógica de criptografia
    }
}

$reflexao = new ReflectionClass('Usuario');

// Obter informações da classe
echo "Nome da classe: " . $reflexao->getName() . "\n";
echo "É instanciável: " . ($reflexao->isInstantiable() ? 'Sim' : 'Não') . "\n";

// Listar métodos
echo "Métodos:\n";
foreach ($reflexao->getMethods() as $metodo) {
    echo "- " . $metodo->getName() . " (" . 
         ($metodo->isPublic() ? 'público' : 'privado') . ")\n";
}

// Listar propriedades
echo "Propriedades:\n";
foreach ($reflexao->getProperties() as $propriedade) {
    echo "- " . $propriedade->getName() . " (" . 
         ($propriedade->isPublic() ? 'público' : 'privado') . ")\n";
}
?>

ReflectionMethod

<?php
$reflexao = new ReflectionClass('Usuario');
$metodo = $reflexao->getMethod('login');

echo "Nome do método: " . $metodo->getName() . "\n";
echo "Número de parâmetros: " . $metodo->getNumberOfParameters() . "\n";
echo "Parâmetros obrigatórios: " . $metodo->getNumberOfRequiredParameters() . "\n";

// Listar parâmetros
foreach ($metodo->getParameters() as $parametro) {
    echo "Parâmetro: " . $parametro->getName();
    if ($parametro->isOptional()) {
        echo " (opcional)";
    }
    echo "\n";
}
?>

Aplicações Práticas

Factory Pattern com Reflexão

<?php
class UsuarioFactory
{
    public static function criar($tipo, $dados = array())
    {
        $classe = 'Usuario' . ucfirst($tipo);
        
        if (!class_exists($classe)) {
            throw new Exception("Tipo de usuário '$tipo' não existe");
        }
        
        $reflexao = new ReflectionClass($classe);
        $objeto = $reflexao->newInstance();
        
        // Configurar propriedades usando reflexão
        foreach ($dados as $propriedade => $valor) {
            if (property_exists($classe, $propriedade)) {
                $objeto->$propriedade = $valor;
            }
        }
        
        return $objeto;
    }
}

class UsuarioAdmin
{
    public $nome;
    public $nivel = 'admin';
}

class UsuarioComum
{
    public $nome;
    public $nivel = 'comum';
}

// Uso
$admin = UsuarioFactory::criar('admin', ['nome' => 'João']);
$comum = UsuarioFactory::criar('comum', ['nome' => 'Maria']);
?>

Validador Automático

<?php
class Validador
{
    public static function validar($objeto)
    {
        $reflexao = new ReflectionClass($objeto);
        $erros = array();
        
        foreach ($reflexao->getProperties() as $propriedade) {
            $nome = $propriedade->getName();
            $valor = $propriedade->getValue($objeto);
            
            // Validação baseada no nome da propriedade
            if (strpos($nome, 'email') !== false) {
                if (!filter_var($valor, FILTER_VALIDATE_EMAIL)) {
                    $erros[] = "Email inválido: $nome";
                }
            }
            
            if (strpos($nome, 'obrigatorio') !== false && empty($valor)) {
                $erros[] = "Campo obrigatório: $nome";
            }
        }
        
        return $erros;
    }
}

class FormularioContato
{
    public $emailObrigatorio;
    public $nomeObrigatorio;
    public $telefone;
}

$formulario = new FormularioContato();
$formulario->emailObrigatorio = 'email-invalido';
$formulario->nomeObrigatorio = '';
$formulario->telefone = '1234567890';

$erros = Validador::validar($formulario);
foreach ($erros as $erro) {
    echo $erro . "\n";
}
?>

Sistema de Plugin Dinâmico

<?php
class GerenciadorPlugins
{
    private $plugins = array();
    
    public function carregarPlugin($nomeClasse)
    {
        if (!class_exists($nomeClasse)) {
            return false;
        }
        
        $reflexao = new ReflectionClass($nomeClasse);
        
        // Verificar se implementa interface de plugin
        if (!$reflexao->implementsInterface('IPlugin')) {
            throw new Exception("$nomeClasse deve implementar IPlugin");
        }
        
        $plugin = $reflexao->newInstance();
        $this->plugins[] = $plugin;
        
        return true;
    }
    
    public function executarPlugins($evento, $dados = array())
    {
        foreach ($this->plugins as $plugin) {
            $reflexao = new ReflectionClass($plugin);
            
            if ($reflexao->hasMethod($evento)) {
                $metodo = $reflexao->getMethod($evento);
                $metodo->invoke($plugin, $dados);
            }
        }
    }
}

interface IPlugin
{
    public function onInit();
}

class PluginLog implements IPlugin
{
    public function onInit()
    {
        echo "Plugin de Log iniciado\n";
    }
    
    public function onUsuarioLogin($dados)
    {
        echo "Usuário logado: " . $dados['nome'] . "\n";
    }
}

// Uso
$gerenciador = new GerenciadorPlugins();
$gerenciador->carregarPlugin('PluginLog');
$gerenciador->executarPlugins('onInit');
$gerenciador->executarPlugins('onUsuarioLogin', ['nome' => 'João']);
?>

Melhores Práticas

1. Use Reflexão com Moderação

  • Performance: Reflexão é mais lenta que acesso direto
  • Complexidade: Pode tornar código difícil de entender
  • Cache: Cache resultados de reflexão quando possível

2. Validação de Entrada

<?php
function chamarMetodo($objeto, $metodo, $parametros = array())
{
    if (!is_object($objeto)) {
        throw new InvalidArgumentException('Primeiro parâmetro deve ser objeto');
    }
    
    if (!method_exists($objeto, $metodo)) {
        throw new BadMethodCallException("Método '$metodo' não existe");
    }
    
    $reflexao = new ReflectionMethod($objeto, $metodo);
    
    if (!$reflexao->isPublic()) {
        throw new BadMethodCallException("Método '$metodo' não é público");
    }
    
    return $reflexao->invokeArgs($objeto, $parametros);
}
?>

3. Documentação Clara

<?php
/**
 * Classe utilitária para introspecção de objetos
 * 
 * Fornece métodos para examinar propriedades e métodos
 * de objetos em tempo de execução usando reflexão PHP
 */
class Introspector
{
    /**
     * Lista todos os métodos públicos de um objeto
     * 
     * @param object $objeto O objeto a ser examinado
     * @return array Lista de nomes dos métodos públicos
     * @throws InvalidArgumentException se o parâmetro não for objeto
     */
    public static function listarMetodosPublicos($objeto)
    {
        if (!is_object($objeto)) {
            throw new InvalidArgumentException('Parâmetro deve ser um objeto');
        }
        
        $reflexao = new ReflectionClass($objeto);
        $metodosPublicos = array();
        
        foreach ($reflexao->getMethods(ReflectionMethod::IS_PUBLIC) as $metodo) {
            $metodosPublicos[] = $metodo->getName();
        }
        
        return $metodosPublicos;
    }
}
?>

Conclusão

Por hoje é só pessoALL!

As funções de manipulação de objetos em PHP são ferramentas poderosas que permitem:

Recursos Aprendidos

  • get_class_methods: Listar métodos de uma classe
  • get_class_vars: Obter propriedades estáticas
  • get_object_vars: Obter propriedades dinâmicas
  • method_exists: Verificar existência de métodos
  • call_user_func: Executar métodos dinamicamente
  • Reflexão: Introspecção avançada de objetos

Aplicações Práticas

  • Factory Pattern: Criação dinâmica de objetos
  • Validação automática: Baseada em convenções
  • Sistemas de plugins: Carregamento dinâmico
  • APIs flexíveis: Métodos configuráveis

Próximos Passos

Na próxima parte abordaremos conceitos mais avançados de orientação a objetos, incluindo herança, polimorfismo e interfaces.

A capacidade de examinar e manipular objetos dinamicamente é uma das características mais poderosas do PHP moderno!

[]‘s