Texto/Compilado por Zhu Xianzhong
1. Introdução
Felizmente, a tecnologia de sobrecarga de objetos foi introduzida no PHP 5.0. Este artigo irá explorar a possibilidade de sobrecarregar os métodos __call(), __set() e __get(). Após uma breve introdução à teoria da sobrecarga, iremos direto ao tópico através de dois exemplos: o primeiro exemplo é implementar uma classe de armazenamento persistente; o segundo exemplo é encontrar uma maneira de implementar getter/setter dinâmico;
2. O que é sobrecarga de objetos?
Ao falar sobre sobrecarga de objetos em PHP, temos que distinguir dois tipos:
· Sobrecarga de métodos
· Sobrecarga de atributos
No caso de sobrecarga de métodos, temos que definir um método mágico __call(), que implementará uma chamada genérica para um método indefinido na classe correspondente. Este método geral é chamado apenas quando você deseja acessar um método indefinido na classe. Sem sobrecarga de método, o exemplo a seguir fará com que o PHP exiba uma mensagem de erro fatal: Chame o método indefinido ThisWillFail::bar() in/some/directory/example.php na linha 9 e aborte a execução do programa:
< ?php
classe ThisWillFail {
função pública foo() {
retorne "Olá, mundo!";
}
}
$class = new ThisWillFail;
$class->bar();
?>
Com a ajuda da sobrecarga de método, o código pode capturar essa chamada e tratá-la normalmente.
A sobrecarga de propriedades é semelhante à sobrecarga de métodos. Nesse caso, a classe redireciona (também chamada de proxy) operações de leitura/gravação para propriedades da classe que não estão explicitamente definidas na classe. Os métodos especializados aqui são __set() e __get(). Dependendo do nível de relatório de erros, o tradutor PHP normalmente emitirá uma notificação ao acessar uma propriedade indefinida ou adiará e potencialmente definirá a variável. Se você usar sobrecarga de atributos, o tradutor poderá chamar __set() ao definir um atributo indefinido e chamar __get() ao acessar um valor de atributo indefinido.
Resumindo, o uso de tecnologia de sobrecarga pode reduzir bastante o tempo de desenvolvimento de software ao usar linguagens dinâmicas como PHP.
Neste ponto, a teoria é introduzida e a codificação específica é analisada a seguir.
3. Exemplos de classes de armazenamento persistente
O código a seguir implementa a classe de armazenamento persistente mencionada acima com menos de 50 linhas de código PHP usando tecnologia de sobrecarga de atributos. O termo persistente significa que a classe pode descrever um elemento de uma estrutura de dados e permanecer sincronizada com o sistema de armazenamento subjacente. Em termos de codificação, o código externo pode usar classes para selecionar uma linha de uma tabela de banco de dados. Desta forma, quando o programa está em execução, você pode acessar diretamente os atributos da classe para manipular os elementos da linha (leitura/busca). Ao final do script, o PHP será responsável por enviar os dados atualizados das linhas de volta ao banco de dados.
Estudar cuidadosamente o código a seguir ajudará você a entender o que é sobrecarga de atributos.
<?php
//Carregar PEAR <a href=" http://pear.php.net/package/DB/ "> Pacote DB</a>
require_once "DB.php";
classe Persistente {
private $dados = array();
private $table = "usuários";
função pública __construct($usuário) {
$this->dbh = DB::Connect("mysql://user:password@localhost/database");
$query = "SELECIONE id, nome, email, país DE " .
$this->tabela. "ONDE nome =?";
$this->data = $this->dbh->getRow($query, array($user),
DB_FETCHMODE_ASSOC);
}
função pública __get($membro) {
if (isset($este->dados[$membro])) {
return $este->dados[$membro];
}
}
função pública __set($membro, $valor) {
//O ID do conjunto de dados é somente leitura if ($member == "id") {
retornar;
}
if (isset($este->dados[$membro])) {
$this->dados[$membro] = $valor;
}
}
função pública __destruir() {
$query = "ATUALIZAÇÃO " . $this->tabela .
email = ?, país = ? ONDE id = ?";
$this->dbh->query($query, $this->nome, $this->email,
$este->país, $este->id);
}
}
$class = new Persistente("Martin Jansen");
$class->nome = "John Doe";
$class->país = "Estados Unidos";
$class->email = " [email protected] ";
?>
O primeiro problema que você pode encontrar é __construct(), o novo método construtor introduzido no PHP 5. Na época do PHP 4, os construtores sempre correspondiam aos nomes de suas classes. Este não é mais o caso no PHP 5. Você não precisa saber muito sobre o método construtor, exceto que chamá-lo cria uma instância de uma classe e observe que um parâmetro é usado aqui - um banco de dados é executado com base nesse parâmetro; Este construtor atribui os resultados da consulta ao atributo de classe $data.
A seguir, o programa define dois métodos especiais __get() e __set(). Você já deve estar familiarizado com eles: __get() é usado para ler valores de atributos indefinidos e __set() é usado para modificar valores de atributos indefinidos.
Isso significa que sempre que uma propriedade indefinida é lida/escrita a partir de uma classe de armazenamento persistente, esses métodos especializados são responsáveis por gerenciar as informações na variável $data da matriz de propriedades, em vez de alterar diretamente as propriedades da classe (lembre-se: A variável $data contém uma linha do banco de dados!).
O último método em uma classe é o oposto de __construct() – o destruidor __destruct(). O PHP chama o destruidor durante a "fase de encerramento do script", que normalmente ocorre próximo ao final da execução de um script PHP. O destruidor grava as informações do atributo $data de volta no banco de dados. Isso é exatamente o que significa o termo anterior sincronização.
Você deve ter notado que o código aqui usa o pacote de camada de abstração de banco de dados do PEAR. Na verdade, não importa. A comunicação com o banco de dados por meio de outros métodos também pode ilustrar o tema deste artigo.
Se você olhar com atenção, descobrirá que a descrição dessa classe de armazenamento persistente é relativamente simples. O exemplo envolve apenas uma tabela de banco de dados e não considera modelos de dados mais complexos, como o uso de LEFT JOIN e outras técnicas complexas de operação de banco de dados. No entanto, você não precisa se limitar a isso e, com a ajuda da sobrecarga de propriedades, pode usar seu próprio modelo de banco de dados ideal. Com apenas um pouco de código, você pode aproveitar os recursos complexos do banco de dados nesta classe de armazenamento persistente.
Há também um pequeno problema - nenhum mecanismo de tratamento de erros é introduzido quando a consulta falha no destruidor. É a natureza dos destruidores que torna impossível exibir uma mensagem de erro apropriada neste caso, porque a construção da marcação HTML geralmente termina antes que o PHP chame o destruidor.
Para resolver esse problema, você pode renomear __destruct() para algo como saveData() e executar esse método manualmente em algum lugar do script de chamada. Isso não muda o conceito de armazenamento persistente para classes; são apenas mais algumas linhas de código. Alternativamente, você pode usar a função error_log() no destruidor para registrar a mensagem de erro em um arquivo de log de erros de todo o sistema.
É assim que funciona a sobrecarga de propriedades. A seguir discutiremos a sobrecarga de métodos.
4. Exemplos de sobrecarga de métodos
1. Métodos Getter/Setter dinâmicos
O código a seguir implementa os métodos getter/setter "dinâmicos" para controlar a classe com a ajuda da sobrecarga de métodos. Vamos analisá-lo com base no código fonte:
<?php
classe DynamicGetterSetter {
private $nome = "Martin Jansen";
private $starbucksdrink = "Redemoinho de Cappuccino Caramelo";
function __call($método, $argumentos) {
$prefixo = strtolower(substr($método, 0, 3));
$propriedade = strtolower(substr($método, 3));
if (vazio($prefixo) || vazio($propriedade)) {
retornar;
}
if ($prefix == "get" && isset($this->$property)) {
retorne $isto->$propriedade;
}
if ($prefixo == "definir") {
$this->$property = $argumentos[0];
}
}
}
$class = novo DynamicGetterSetter;
echo "Nome: " . $class->getNome() .
echo "Sabor Starbucks favorito: " $class->getStarbucksDrink() .
$class->setName("John Doe");
$class->setStarbucksDrink("Café Clássico");
echo "Nome: " . $class->getNome() .
echo "Sabor Starbucks favorito: " $class->getStarbucksDrink() .
?>
Obviamente, os dois atributos $name e $starbucksdrink aqui são privados, o que significa que esses atributos não podem ser acessados de fora da classe. Na programação orientada a objetos, é muito comum implementar métodos getter/setter públicos para acessar ou modificar os valores de propriedades não públicas. Implementá-los é tedioso e consome tempo e esforço.
Este problema pode ser facilmente resolvido com a ajuda da sobrecarga de métodos. Em vez de implementar métodos getter/setter para cada propriedade, o acima implementa apenas um método __call() geral. Isso significa que quando um método getter/setter indefinido como setName() ou getStarbucksdrink() é chamado, o PHP não irá gerar um erro fatal e abortar, mas em vez disso executará (ou delegará) o método mágico __call().
Estas são algumas breves introduções. Vamos fazer uma análise aprofundada de __call().
2. Análise detalhada do método __call()
O primeiro parâmetro de __call() é o método original e indeterminado (como setName). O segundo parâmetro é uma matriz unidimensional com um índice numérico, que contém todos os métodos originais. parâmetro. Chamar um método indefinido com dois parâmetros ("Martin" e 42) produzirá o seguinte array:
$class->thisMethodDoesNotExist("Martin", 42);
/Guia para o segundo parâmetro de __call()
Variedade
(
[0] =>Martinho
[1] => 42
)
Dentro do método __call(), se o método original começar com get ou set, algum cálculo deverá ser realizado para determinar se o código chama um método getter/setter. Além disso, este método analisará ainda mais outro componente do nome do método (exceto os três primeiros caracteres), porque a última parte da string representa o nome do atributo referenciado pelo getter/setter.
Se o nome do método indicar um getter/setter, o método retornará o valor da propriedade correspondente ou definirá o valor do primeiro parâmetro do método original. Caso contrário, não faz nada e continua executando o programa como se nada tivesse acontecido.
3. Para atingir o objetivo
Em essência, correspondendo a qualquer atributo, existe um método que permite ao código chamar dinamicamente qualquer método getter/setter. Este algoritmo existe. Isso é conveniente ao desenvolver um protótipo de programa no curto prazo: em vez de gastar muito tempo implementando getters/setters, o desenvolvedor pode se concentrar na modelagem da API e em garantir que o aplicativo esteja fundamentalmente correto. Incorporar o método __call() em uma classe abstrata pode até permitir a reutilização de código no desenvolvimento futuro de projetos PHP.
4. Além das deficiências,
existem vantagens e desvantagens! Existem várias desvantagens na abordagem acima: Projetos maiores podem usar ferramentas como o phpDocumentor para rastrear a estrutura da API. Com o método dinâmico apresentado acima, é claro que todos os métodos getter/setter não aparecerão no documento gerado automaticamente, o que não requer maiores explicações.
Outra desvantagem é que o código fora da classe pode acessar todas as propriedades privadas dentro da classe. Ao usar métodos getter/setter reais, é possível distinguir entre propriedades privadas que podem ser acessadas por código externo e propriedades privadas "reais" que não são visíveis fora da classe - porque temos sobrecarga de métodos e temos getters e setters virtuais Métodos podem ser usados.
5. Conclusão
Este artigo analisa cuidadosamente as duas situações de sobrecarga de objetos no PHP 5.0 através de dois exemplos. Espero sinceramente que o método deste artigo possa ajudá-lo a melhorar a eficiência da programação PHP. Ao mesmo tempo, você também verá claramente as deficiências desse método!