Extendendo dinamicamente uma classe
Para a solução do problema inicial eu preciso de:
1. Arquivos separados para cada função extra (plugin).
2. Uma função para carregar o conteúdo destes arquivos.
3. Uma função que incluirá a nova função à classe atual.
Note que a função 2 pode estar incluída na 3, mas vou deixar separado para facilitar a explicação.
A nossa classe principal:
1. Arquivos separados para cada função extra (plugin).
Note que não é necessário passar o objeto como referência e agora eu utilizo a variável $this pois a função será interna à classe.
2. Função para carregar o conteúdo dos arquivos.
3. Função que incluirá a nova função à classe atual.
Como utilizar:
Como falei antes, você pode juntar as funções "plugin" e "extend".
Também não coloquei nenhuma verificação para ver se a função existe ou já está carregada.
É possível fazer uma função externa que extenda qualquer classe, passando-a por referência.
Espero que esta dica seja útil pra você.
Um abraço,
-- db
1. Arquivos separados para cada função extra (plugin).
2. Uma função para carregar o conteúdo destes arquivos.
3. Uma função que incluirá a nova função à classe atual.
Note que a função 2 pode estar incluída na 3, mas vou deixar separado para facilitar a explicação.
A nossa classe principal:
<?php class foo { var $value=1; function plugin($nome_plugin){ // veja item 2 } function extend($codigo){ // veja item 3 } } ?>
1. Arquivos separados para cada função extra (plugin).
<?php // bar.php function bar($soma) { $this->value = $this->value + $soma; } ?>
Note que não é necessário passar o objeto como referência e agora eu utilizo a variável $this pois a função será interna à classe.
2. Função para carregar o conteúdo dos arquivos.
<?php // Função "plugin" da classe "foo" function plugin($nome_plugin) { $conteudo = file("/caminho/ate/os/plugins/".$nome_plugin.".php"); // A primeira linha do arquivo deve conter a tag que abre o código PHP ex. '<?php' // A última linha deve conter a tag que fecha o código PHP $total_linhas = count($conteudo); unset($conteudo[0]); // exclui primeira linha unset($conteudo[$total_linhas-1]); // exclui última linha $conteudo = implode("",$conteudo); // conteúdo do arquivo $this->extend($conteudo); } ?>
3. Função que incluirá a nova função à classe atual.
<?php // Função "extend" da classe "foo" function extend($codigo) { $nome_classe = get_class($this); $nome_nova_classe = $nome_classe . "_ext"; eval('class '. $nome_nova_classe .' extends '. $nome_classe .' { '. $codigo .' }'); $this = new $nome_nova_classe(); } ?>
Como utilizar:
<?php $foo = new foo; $foo->plugin('bar'); $foo->bar(7); // retorna 8 $foo->bar(9); // retorna 17 (8+9) ?>
Como falei antes, você pode juntar as funções "plugin" e "extend".
Também não coloquei nenhuma verificação para ver se a função existe ou já está carregada.
É possível fazer uma função externa que extenda qualquer classe, passando-a por referência.
Espero que esta dica seja útil pra você.
Um abraço,
-- db
Realmente Hugo isto acontece. Percebi outro dia no meu projeto. Uma forma de corrigir isso aí é copiando todas as variáveis da classe na nova extendida:
<?php
// Função "extend" da classe "foo"
function extend($codigo) {
$nome_classe = get_class($this);
srand((double)microtime()*1000000);
$nome_nova_classe = $nome_classe . rand(0,99);
eval('class '. $nome_nova_classe .' extends '. $nome_classe .' { '. $codigo .' }');
$obj = new $nome_nova_classe();
$vars = get_class_vars($nome_classe);
foreach($vars AS $key=>$value) {
$obj->$key = &$this->$key;
}
$this = $obj;
unset($obj);
}
?>
<?php
// Função "extend" da classe "foo"
function extend($codigo) {
$nome_classe = get_class($this);
srand((double)microtime()*1000000);
$nome_nova_classe = $nome_classe . rand(0,99);
eval('class '. $nome_nova_classe .' extends '. $nome_classe .' { '. $codigo .' }');
$obj = new $nome_nova_classe();
$vars = get_class_vars($nome_classe);
foreach($vars AS $key=>$value) {
$obj->$key = &$this->$key;
}
$this = $obj;
unset($obj);
}
?>
14/12/2003 2:06pm
(~21 anos atrás)
Qdo vc carregar o plugin vc vai perder todos os atributos da classe não? sendo obrigado a carregar o plugin antes de mecher em qualquer coisa da classe....
14/12/2003 1:17pm
(~21 anos atrás)
Muito bem lembrado Eduardo. Nem tinha me tocado disso.
Uma maneira de corrigir isso é substituir a linha da função 'extend':
$nome_nova_classe = $nome_classe . "_ext";
por:
srand((double)microtime()*1000000);
$nome_nova_classe = $nome_classe . rand(0,999);
A probabilidade de redeclarar uma classe cai bastante usando esse código.
Uma maneira de corrigir isso é substituir a linha da função 'extend':
$nome_nova_classe = $nome_classe . "_ext";
por:
srand((double)microtime()*1000000);
$nome_nova_classe = $nome_classe . rand(0,999);
A probabilidade de redeclarar uma classe cai bastante usando esse código.
21/11/2003 2:00pm
(~21 anos atrás)
Ocorre um problema junto ao codigo explicado: quando eu tenho diversos objetos que de uma mesma classe e crio dinamicamente esta extensão ele emitira um erro dizendo que no pode redeclarar a classe, sendo necessario ( julgo melhor ).. alterar em vez de *_ext ser *_(nome do objeto )...
Abraços
Abraços
21/11/2003 1:04pm
(~21 anos atrás)
explicou direitinho sim.. entendi
fica bem dinâmico e interessante de se trabalhar deste jeito que você falou
tem algum grande projeto que você desenvolveu baseando-se neste esquema proposto no artigo ?
fica bem dinâmico e interessante de se trabalhar deste jeito que você falou
tem algum grande projeto que você desenvolveu baseando-se neste esquema proposto no artigo ?
18/11/2003 11:47am
(~21 anos atrás)
Olha, no fundo é isso que a função 'extend' está fazendo usando eval(). Vou tentar explicar a vantagem.
Do jeito que você está falando, para usar a função 'foo_foo_foo', você tem que criar um objeto assim:
<?php
$myfoo = new myfoo;
?>
O jeito que eu estou propondo é concentar tudo na classe base (ou "brain" como você chamou =) ).
<?php
$foo = new foo;
$foo->plugin('myfoo');
$foo->foo_foo_foo();
?>
Aqui não vemos muitas vantagens, mas se tivermos mais plugins? Do jeito que você está falando:
<?php
$myfoo = new myfoo;
$yourfoo = new yourfoo;
$ourfoo = new ourfoo;
// ...
?>
Ou seja, preciso ter diversos objetos individuais para cada plugin.
Se usar a função 'plugin':
<?php
$foo = new foo; // base
$foo->plugin('myfoo');
$foo->plugin('yourfoo');
$foo->plugin('ourfoo');
?>
Você tem disponível todas os plugins no mesmo objeto $foo. Não é legal? =)
Realmente eu sei que o PEAR, e outras clases funcionam deste jeito que você falou. Mas num projeto recente eu vi vantagem de usar tal método.
A explicação que eu vejo para o PEAR usar desta maneira é que as classes que extendem a base PEAR são grandes e completas, com grande número de funções. Assim, você utilizará somente a nova classe que extende PEAR.
Em se tratando de um grande número de funções extras que você queira incorporar, onde em um script você precisa somente de certo plugin e em outro um plugin diferente, chamar dinamicamente tais funções, individualmente, é, ao meu ver, uma vantagem.
Neste caso seriam diversas funções que tem propósitos diferentes e que não tem relação umas com as outras, não havendo vantagem em juntar em uma classe única que extende a base.
Espero que tenha explicado meu ponto de vista. =)
Um abraço!
Do jeito que você está falando, para usar a função 'foo_foo_foo', você tem que criar um objeto assim:
<?php
$myfoo = new myfoo;
?>
O jeito que eu estou propondo é concentar tudo na classe base (ou "brain" como você chamou =) ).
<?php
$foo = new foo;
$foo->plugin('myfoo');
$foo->foo_foo_foo();
?>
Aqui não vemos muitas vantagens, mas se tivermos mais plugins? Do jeito que você está falando:
<?php
$myfoo = new myfoo;
$yourfoo = new yourfoo;
$ourfoo = new ourfoo;
// ...
?>
Ou seja, preciso ter diversos objetos individuais para cada plugin.
Se usar a função 'plugin':
<?php
$foo = new foo; // base
$foo->plugin('myfoo');
$foo->plugin('yourfoo');
$foo->plugin('ourfoo');
?>
Você tem disponível todas os plugins no mesmo objeto $foo. Não é legal? =)
Realmente eu sei que o PEAR, e outras clases funcionam deste jeito que você falou. Mas num projeto recente eu vi vantagem de usar tal método.
A explicação que eu vejo para o PEAR usar desta maneira é que as classes que extendem a base PEAR são grandes e completas, com grande número de funções. Assim, você utilizará somente a nova classe que extende PEAR.
Em se tratando de um grande número de funções extras que você queira incorporar, onde em um script você precisa somente de certo plugin e em outro um plugin diferente, chamar dinamicamente tais funções, individualmente, é, ao meu ver, uma vantagem.
Neste caso seriam diversas funções que tem propósitos diferentes e que não tem relação umas com as outras, não havendo vantagem em juntar em uma classe única que extende a base.
Espero que tenha explicado meu ponto de vista. =)
Um abraço!
18/11/2003 10:37am
(~21 anos atrás)
cara, seu artigo é muito legal, só que
eu estava vendo o padrão da pear e algumas classes que estou usando, e reparei o seguinte:
há um arquivo PEAR.php com a classe
e como você disse para não "sujar" muito a classe com coisas desnecessarias cria-se o "brain" do negocio que fica nesse arquivo ai..
e um novo codigo é feito num outro arquivo php
foo.php
com uma classe
<?php
class myfoo extends PEAR {
function foo_foo_foo
}
?>
dai você trabalha chamando o PEAR.php
e eventualmente os teus packages né..
tuas subclasses, teus features sei lá.. nomeação é o que não falta..
mas seria uma outra forma de estar trabalhando não ?
bom, é isso!
Abraços!
eu estava vendo o padrão da pear e algumas classes que estou usando, e reparei o seguinte:
há um arquivo PEAR.php com a classe
e como você disse para não "sujar" muito a classe com coisas desnecessarias cria-se o "brain" do negocio que fica nesse arquivo ai..
e um novo codigo é feito num outro arquivo php
foo.php
com uma classe
<?php
class myfoo extends PEAR {
function foo_foo_foo
}
?>
dai você trabalha chamando o PEAR.php
e eventualmente os teus packages né..
tuas subclasses, teus features sei lá.. nomeação é o que não falta..
mas seria uma outra forma de estar trabalhando não ?
bom, é isso!
Abraços!
17/11/2003 7:22pm
(~21 anos atrás)
Bom, se você não entende porque nao vê vantagens veja um outro artigo (hehe, sem propagandas) do André de Castro Zorzo que fala sobre classes no PHP também.
Espero ter ajudado
Espero ter ajudado
17/11/2003 7:16pm
(~21 anos atrás)
Valeu ae.. eu não aprendo muito bem as classes por que não consigo enxergar realmente a vantagem de utilizá-las. :).
Vou ver se dou uma lida sobre isso por aí! Valeu a ajuda!
Vou ver se dou uma lida sobre isso por aí! Valeu a ajuda!
17/11/2003 6:37am
(~21 anos atrás)
O JavaScript abaixo não roda através do navegador Firefox. Será que VC poderia me ajudar alterando algum(s) parâmetro(s) ? Agradeço desde já = Fiumari:
<script language="JavaScript"> var ultimo=-1, dBanner;
function carrega(x) {dBanner=x;Banners()}
function Banners()
{ var MNews = new Array();
MNews[0]= '<iframe " name="_blank" scrolling="no" src="http://www.finet.com.br/google.htm" width="100%" frameborder="0" target="_blank" height="350" BORDER="0"></iframe><a href="http://www.finet.com.br/google.htm" target="_blank"></a>';
MNews[1]= '<iframe " name="_blank" scrolling="no" src="http://www.finet.com.br/google2.htm" width="100%" frameborder="0" target="_blank" height="350" BORDER="0"></iframe><a href="http://www.finet.com.br/google2.htm" target="_blank"></a>'
while((Numero = parseInt(Math.random()*MNews.length))==ultimo);
dBanner.innerHTML=MNews[Numero];
setTimeout("Banners()",15000);
} </script>