PHP:Como implementar um método __get-like para variáveis de função local
Pergunta
Não sou estranho ao __get() e já o usei para criar algumas bibliotecas muito convenientes no passado.Porém, me deparo com um novo desafio (PHP 5.3, abreviou e simplificou meu código para esta questão):
<?php
namespace test;
class View {
function __construct($filename, $varArray) {
$this->filename = $filename;
$this->varArray = $varArray;
}
function display() {
include($this->filename);
}
function __get($varName) {
if (isset($this->varArray[$varName]))
return $this->varArray[$varName];
return "?? $varname ??";
}
}
?>
Acima está um sistema muito, muito simplificado para carregar uma View.Este código chamaria a visualização e a exibiria:
<?php
require_once("View.php");
use test\View;
$view = new View("views/myview.php", array("user" => "Tom"));
$view->display();
?>
Meu objetivo com este código é permitir que a visualização "myview.php" contenha código como este:
<p>
Hello <?php echo $user; ?>! Your E-mail is <?php echo $email; ?>
</p>
E, usado com o código acima, geraria "Olá Tom!Seu e-mail é ??e-mail ??"
No entanto, isso não funcionará.A visualização está sendo incluída em um método de classe, portanto, quando se refere a $user e $email, está procurando variáveis de função locais - não variáveis pertencentes à classe View.Por esse motivo, __get nunca é acionado.
Eu poderia mudar todas as variáveis da minha visão para coisas como $this->user e $this->email, mas isso seria uma solução confusa e pouco intuitiva.Eu adoraria encontrar uma maneira de referenciar variáveis diretamente, SEM que o PHP gere um erro quando uma variável indefinida for usada.
Pensamentos?Existe uma maneira limpa de fazer isso ou sou forçado a recorrer a soluções hacky?
Solução
EDITANDO MINHA RESPOSTA.Um pouco como um "hackear", mas uma solução potencial.Pode querer "redefinir" o error_handler para uma funcionalidade mais genérica.
visualizar.php
<?php
error_reporting(E_ALL);
ini_set("display_errors", 0);
class View {
function display($file, $values) {
set_error_handler(array($this, '__get'), E_NOTICE);
extract($values);
include($file);
}
function __get($vaule)
{
echo '<i>Unknown</i>';
}
}
$View = new View;
$values = array('user' => 'Tom',
'email' => 'email@host.com');
$View->display('/filename.php', $values);
?>
nome do arquivo.php
Hello <?php echo $user; ?>, your email is <?php echo $email; ?> and your are <?php echo $age; ?> years old.
Saída
Hello Tom, your email is email@host.com and your are
Desconhecido years old.
Outras dicas
Você pode usar extrair para colocar todas as variáveis no escopo local:
function display() {
extract($this->varArray);
include($this->filename);
}