Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
Ola.
Recentemente, eu li em um artigo do imasters (
http://imasters.com.br/artigo/21215/php/a-nova-era-de-frameworks-php
) que usar os métodos mágicos na orientação a objetos com php não é recomendável, porque eles deixam o código obscuro.
Sinceramente, não entendi o que o autor queria dizer com isso.
Alguém pode me explicar qual o problema em usá-lo e o que eu poderia usar para substituir sua funcionalidade?
Obrigado.
como é? não entendi nada.
Os métodos mágicos podem deixar lento sua aplicação pois trabalham com muitos recursos do PHP o que exige mais do servidor.
os únicos métodos mágicos que eu utilizo são:
__construct
__destruct
__toString
__clone
Na minha opnião, métodos mágicos como __set e __get, quando utilizados para o desenvolvimento de uma classe, faz com que, o desenvolvedor, que não desenvolveu a classe mas irá utilizá-la, precisa ser "mágico" para descobrir os atributos que uma classe possui.
>
os únicos métodos mágicos que eu utilizo são:
__construct
__destruct
__toString
__clone
Na minha opnião, métodos mágicos como __set e __get, quando utilizados, o desenvolvedor precisa ser "mágico" para descobrir os atributos que uma classe possui.
simplesmente pq o mesmo nao documentou a classe neh, muitos nao o fazem e se perdem..eu ja fui um deles, hj documento tudo, desde uml at phpdoc...na minha opiniao os metodos magicos eh o q deixa o php dinamico, mais flexivel, pois muitas linguagem esbarram ora na tipagem ora no dinamismo...
Alguém poderia me dar um exemplo?
Para mim, os métodos mágicos são algo bom, não entendo qual o problema.
>
simplesmente pq o mesmo nao documentou a classe neh, muitos nao o fazem e se perdem[...]
Exatamente!!!
Talvez por eu ter aprendido OO no java, eu seja meio cético quanto essa flexibilidade do PHP.
Eu vejo a flexibilidade como uma brecha para despadronizações ( assim como aconteceu ao HTML. Depois foi criado o XHTML para resolver isso ).
Por isso gosto da inflexibilidade que o Java tem, e tudo que construo em PHP, me baseio em Java.
E também deixo uma citação do João Batista Neto do seu artigo PHPog: uma questão de design?
[...]Se você não ler o código, você não vai saber que esse objeto pode voar, ou seja, esses ditos métodos mágicos não são realmente mágicos, na verdade são feitos para que programadores que possuem poderes mágicos ou uma bola de cristal possam utilizar.[...]
Eu vejo a flexibilidade como uma brecha para despadronizações ( assim como aconteceu ao HTML. Depois foi criado o XHTML para resolver isso ).
se fosse assim, os contorcionistas ficariam com seus corpos deformados...
muitos fazem
$id = $_GET['id'];
mas seuqer fazem devida validacao...nao eh regra, mas eh deixar brecha de seguranca, assim como tb ocorre em java,
public Integer i = "test";
o java tb vai chiar, por conta da nao validacao...
tudo depende do programador...tudo...
Por isso gosto da inflexibilidade que o Java tem, e tudo que construo em PHP, me baseio em Java.
cada linguagem tem suas facilidades e dificuldades, por isso nao deveria se basear numa linguagem pra escrever outra, se fosse assim, eu faria
int $var;
no php, nao sao a mesma coisa...
E também deixo uma citação do João Batista Neto do seu artigo PHPog: uma questão de design?
[...]Se você não ler o código, você não vai saber que esse objeto pode voar, ou seja, esses ditos métodos mágicos não são realmente mágicos, na verdade são feitos para que programadores que possuem poderes mágicos ou uma bola de cristal possam utilizar.[...]
Joao eh admiravel, porem você deveria se basear em suas experiencias, e nao nas dos outros, ker q alguem viva sua vida por você?
porem você deveria se basear em suas experiencias, e nao nas dos outros, ker q alguem viva sua vida por você?
Quando eu estudei as normas da ABNT artigos/trabalhos científicos. Citação era uma forma de utilizar a opinião de outra pessoa em prol do que eu estou defendendo. Acredito que ainda não tenha mudado (ainda, mudaram até a trema '-'). Então, só utilizei o que ele falou em prol da minha opinião sobre métodos mágicos. E sobre minha experiência em PHP:
[...]por isso nao deveria se basear numa linguagem pra escrever outra, se fosse assim, eu faria
int $var;
no php, nao sao a mesma coisa...[...]
bem que eu gostaria de poder escrever tudo no PHP como se escreve em Java.
Mas por exemplo.
Se eu for escrever um método como este:
public function setInt( int $int ) {
...
}
Na hora que eu for chamá-lo, o PHP dirá que eu estou passando um Integer quando o esperado era um int.
se eu for mudar para:
public function setInt( Integer $int ) {
...
}
O PHP irá emitir o mesmo erro, só que dessa vez, dirá que eu estou passando um Integer quando o esperado era um Integer (WTF???????)
Sim, eu já testei.... gostaria que o type hinting do PHP fosse tão bom quanto do Java. Eu posso viver com isso, não disse que não.
Utilizando um exemplo bem chulo: É como pegar alguém que fez a cirurgia de mudança de sexo, o "resultado" é o mesmo. Mas, lá no fundo, é diferente e eu não gosto dessa diferença. '-'
Voltando ao PHP, eu posso "viver" com as diferenças, só não gostaria de muitas delas.
Eu estou lendo um livro do Pablo Dall'Oglio chamado "PHP - Programando com Orientação a Objetos".
Neste livro ele apresenta os métodos mágicos __set, __get e __call.
A funcionalidade oferecida por estes métodos é bem interessante, mas como dizem que não é recomendável, existe alguma solução orientada a objetos para implementar sua funcionalidade? (ressalto que li o artigo "PHPog: uma questão de design?" de João Batista Neto, citado pelo Gabriel, mas o que ele apresenta não é exatamente uma solução a estes métodos mágicos especificamente falando.
@gabriel, pois eh, muitos programdores php nao documentam, a maioria pq aprendem php em tutoriais q nao estimula a documentar, o oposto do java, se ver aki no forum, muitos sequer usam a busca, postam a mesma duvida varias vezes (os imaturos e preguiçosos ainda t dao '-1' se você postar um link q o ajuda)
o type hinting varia de IDE pra IDE
o php eh dinamico, muitas coisas q atrapalham, dificultam e delongam...o compilador do php foi feito pra interpretar e converter ele mesmo, por exemplo você pode converter uma string pra int ou vice-versa em php, em java nao eh possivel, você tem q fazer na mao...
Ainda não responderam minha pergunta.
Será que podem colocar alguns exemplos?
@Igor.php
Não digo que o PHP não possui seu méritos.
Além do que você já citou, o PHP também possui array dinâmicos (Java somente com ArrayList ou Vector), programação procedural (Java somente OO), uma vasta quantidade de bibliotecas que poucos programadores conhecem (a SPL por exemplo) e muitos outros benefícios sobre qualquer linguagem de programação. Todas as linguagens tem seus méritos, só tenho o direito de não concordar com alguns ou muitos deles. E esse tipo de discussão (do tipo abordagem de assunto e não ofensivo), como a nossa, é importante para ver diferentes pontos de um mesmo "problema/solução".
Bom, para não perder o foco no assunto, como falei anteriormente, acho métodos mágicos são ruins para uma "boa" programação. Entretanto, eles facilitam o desenvolvimento e acrescentam uma flexibilidade a linguagem. Vai de cada um utilizar ou não. Só o fato de você utilizar __set ou __get, te poupa um bom tempo criando setteres e getteres...
__call e __callStatic, facilitam na hora do overload de métodos, já que o overload do php é bem precário. Mas vai de cada desenvolvedor mesmo.
>
@Igor.php
Não digo que o PHP não possui seu méritos.
Além do que você já citou, o PHP também possui array dinâmicos (Java somente com ArrayList ou Vector), programação procedural (Java somente OO), uma vasta quantidade de bibliotecas que poucos programadores conhecem (a SPL por exemplo) e muitos outros benefícios sobre qualquer linguagem de programação. Todas as linguagens tem seus méritos, só tenho o direito de não concordar com alguns ou muitos deles. E esse tipo de discussão (do tipo abordagem de assunto e não ofensivo), como a nossa, é importante para ver diferentes pontos de um mesmo "problema/solução".
Bom, para não perder o foco no assunto, como falei anteriormente, acho métodos mágicos são ruins para uma "boa" programação. Entretanto, eles facilitam o desenvolvimento e acrescentam uma flexibilidade a linguagem. Vai de cada um utilizar ou não. Só o fato de você utilizar __set ou __get, te poupa um bom tempo criando setteres e getteres...
__call e __callStatic, facilitam na hora do overload de métodos, já que o overload do php é bem precário. Mas vai de cada desenvolvedor mesmo.
entao você chegou onde eu keria chegar
@andre
(ressalto que li o artigo "PHPog: uma questão de design?" de João Batista Neto, citado pelo Gabriel, mas o que ele apresenta não é exatamente uma solução a estes métodos mágicos especificamente falando. )
concordo
muitos aki falam de problemas, mas solucoes nao aparecem...
Um pequeno exemplo, peguei alguns dos métodos mágicos que eu acho os mais utilizados (não documentei por falta de tempo e na função clone,do modo que eu implementei, o correto seria emitir um Error e não um Notice, para parar a execução do script):
classe Classe
class Classe {
/ atributos /
private $data = array();
/** métodos mágicos **/
public function __construct() {
echo 'construtor<br/>';
}
public function __destruct() {
echo 'destrutor<br/>';
}
public function __call( $nomeMetodo, $argumentos) {
printf( "Chamando metodo '%s'. Argumentos: %s<br/>", $nomeMetodo, implode(', ', $argumentos) );
}
public static function __callStatic($nomeMetodo, $argumentos) {
printf( "Chamando metodo estático '%s'. Argumentos: %s<br/>", $nomeMetodo, implode(', ', $argumentos) );
}
public function __clone() {
trigger_error('Não é permitido clonar a classe.', E_USER_NOTICE);
}
public function __get( $nomeAtributo ) {
return $this->data[$nomeAtributo];
}
public function __set( $nomeAtributo, $valorAtributo ) {
$this->data[$nomeAtributo] = $valorAtributo;
}
public function __toString() {
$string = '
Classe de nome Classe <br/>
Possui os seguintes atributos <br />';
foreach( $this->data AS $key => $valor ) {
$string .= sprintf( 'Atributo: %s -> Valor: %s <br/>', $key, $valor );
}
return $string;
}
}
Utilizando:
$classe = new Classe();
$classe->nome = 'Gabriel';
$classe->sobrenome = 'Heming';
$classe->funcao = 'Desenvolvedor';
$classe->voa();
Classe::voa();
$classe2 = clone $classe;
echo $classe;
Saída esperada:
construtorChamando metodo 'voa'. Argumentos:
Chamando metodo estático 'voa'. Argumentos:
( ! ) Notice: Não é permitido clonar a classe. in C:\wamp\www\teste.php on line 27
Classe de nome Classe
Possui os seguintes atributos
Atributo: nome -> Valor: Gabriel
Atributo: sobrenome -> Valor: Heming
Atributo: funcao -> Valor: Desenvolvedor
destrutor
Esse é apenas um pequeno exemplo, existem muitas coisas que podem ser feitas com os métodos mágicos, seria algo como "deixa a imaginação rolar". Esse é o meu medo '-'
#1
deixam o código obscuro.Sinceramente, não entendi o que o autor queria dizer com isso.
:seta:
#9
na verdade são feitos para que programadores que possuem poderes mágicos ou uma bola de cristal possam utilizar
Discordo que método mágicos obscurecem o código.
A obscuridade se instaura quando há indisciplina no uso de tais métodos, resolvendo QUALQUER problema com métodos mágicos.
Poxa, __set(), __get(), __isset() e __unset() são os componentes básicos que permitem à uma View Engine proporcionar simplicidade e, até mesmo, mais elegância no código.
Pra mim é muito mais preferível setar nos Controllers:
$this -> view -> name = 'Bruno Augusto';
E no Template, invocar:
<?php echo $this -> name; ?>
Ao invés de:
$this -> view -> assign( 'name', 'Bruno Augusto' );
E no Template, invcar:
<?php echo $this -> getVar( 'name' ); ?>
E o __toString() então.
É muito útil para depurações, identificação de Objetos em uma Coleção (por nome), visualização de um SQL montado com base no Query Object sem a necessidade de um getter e muito mais.
__sleep(), __wakeup() e __clone não posso dizer muita coisa porque ainda não os uso/usei.
Mas o maior vilão da história é __call(). A funcionalidade oferecida por ele, se bem planejada, pode permitir que uma ponte seja criada entre diferentes classes.
Mas o uso irracional desse método acaba até mesmo por forçar uma herança múltipla entre classes o que não é de todo errado (olha as Traits do PHP 5.4 aí), mas se você precisa MESMO de herança múltipla, precisa, primeiro, rever seus conceitos de Orientação a Objetos.
Falou e disse, concordo plenamente...
Já estava triste achando que o tópico iria acabar, e fico feliz por todo o conhecimento que pode-se agregar com esse tópico.
>
A obscuridade se instaura quando há indisciplina no uso de tais métodos, resolvendo QUALQUER problema com métodos mágicos.
Concordo plenamente. E essa indisciplina vem daqueles que eu mencionei, por experiência, que utilizam os métodos mágicos. Então, boa parte da minha opinião, e de qualquer um, vem das experiências, e a minhas não foram lá das muito boas.
>
Poxa, __set(), __get(), __isset() e __unset() são os componentes básicos que permitem à uma View Engine proporcionar simplicidade e, até mesmo, mais elegância no código.
Pra mim é muito mais preferível setar nos Controllers:
$this -> view -> name = 'Bruno Augusto';
E no Template, invocar:
<?php echo $this -> name; ?>
Ao invés de:
$this -> view -> assign( 'name', 'Bruno Augusto' );
E no Template, invcar:
<?php echo $this -> getVar( 'name' ); ?>
Esse eu tenho que concordar em partes, pois seu exemplo é válido e muito bem aplicado.
Mas discordo do uso de __set e __get quando um objeto precisa possuir seus atributos bem definidos e validados.
Se o uso for somente inserir e pegar o valor de um atributo, __set e __get são os mais recomendados. Mas caso dos atributos necessitarem serem validados, e ainda mais com o uso de exception, e manter um encapsulamento, não é nem um pouco recomendável. Também lembro de uma citação de um Engenheiro de Software sobre os métodos get e set (em geral, não métodos mágicos), ele falou que "Se os atributos não precisarem ser validados e você vai fazer get e set somente para ter, coloque os atributos como públic e evite mais métodos inúteis.
Como falei acima, nesse exemple, é o mais recomendável mesmo, pois não há como definir as variáveis em uma view. Mas há casos que eles não podem de maneira alguma serem utilizados.
De longe, acredito que os melhores métodos mágicos implementados foram: __construct(), __destruct(), __toString(), __clone().
Também não posso falar sobre os métodos __sleep() e __wakeup().
E ainda mais concordo com o que foi dito sobre os métodos __call em comparação com traits. Pra falar a verdade, até agora, a melhor implementação de traits que já vi, foi aqui no fórum com Singleton.
Acho que o que mais posso agregar ao tópico, é o fato de em determinados momentos alguns métodos mágicos serem extremamente úteis e em outros devem ser ignorados.
Mas caso dos atributos necessitarem serem validados, e ainda mais com o uso de exception, e manter um encapsulamento, não é nem um pouco recomendável.
Não sei até que ponto isso pode ser verdade.
Por exemplo, na minha View Engine eu tenho uma lista de Variáveis Reservadas cujo nomes não podem ser utilizados em Variáveis de Template, pois tais variáveis oferecem recursos "de fábrica" para ser usados no templates.
E dessa forma, eu tenho no método __set() uma verificação contra essa lista. Se por acaso o nome da variável desejada tiver restrições, uma Exception é disparada.
E tal Exception é automaticamente capturada pelo Dispatcher, parte do Front Controller, da aplicação, anulando qualquer possibilidade de loop infinito devido ao Exception Handler.
Também lembro de uma citação de um Engenheiro de Software sobre os métodos get e set (em geral, não métodos mágicos), ele falou que "Se os atributos não precisarem ser validados e você vai fazer get e set somente para ter, coloque os atributos como públic e evite mais métodos inúteis.
Bom, relutei MUITO em acatar a "Lei" que propriedades NUNCA devem ser públicas. Quando finalmente entendi o real motivo e refleti sobre assunto, tive de dar o braço a torcer e concordar porquê isso é tão errado.
Então, imagine criar o objeto PessoaFisica, e for inserir o CPF
Na minha concepção, os dados devem ser validados no set, e não na hora de inserir no banco de dados ou outros afins.
Então, com o __set, teria que verificar se foi inserida a variável cpf, que pode ser também CPF, Cpf ou até CpF. Isso se resolve com strcasecmp ou expressões regulares, sem problemas. Sem falar de quando "um cara que programa" (vide Willian Bruno) setaria PessoaFisica::cadastro_pessoa_fisica(). Pode ser que você criou toda a classe, documentou tudo, mas ninguém pode garantir que o "cara que programa" irá ler ou, e ao caso de ler, usar da forma correta.
Mas a cada __set você vai ter que fazer essa validação? Acho isso sem propósito, uma vez que implementado o método setCpf, só, e somente só, nele será inserido o CPF.
Bom, essa é a minha visão, para a validação de um cpf, e somente cpf, não é nada de mais, mas quando entram inúmeras validações e a cada validação você vai ter que verificar se o inserido é o necessário.
Pode ser que você criou toda a classe, documentou tudo, mas ninguém pode garantir que o "cara que programa" irá ler ou, e ao caso de ler, usar da forma correta.
dae as exceptions...
Mas agora vem um dilema, o que é melhor, criar exceptions para tudo que pode ser inserido pelo método mágico ou apenas criar um método com sua devida exception?
Como falei anteriormente, varia com o objeto. Vai depender qual objeto, para ai sim, definir o que é melhor ou não. Isso ficou mais que claro.
Então...
No meu caso, o __set() está implementado na View, que é utilizada quando as informações vêm do banco de Dados e não quando elas vão.
Quando elas vão, o __set() da vez seria o classe da Entidade e, ainda não me convenceram do porquê de validar os dados no Model, vejo tal processo de usabilidade doo Controller, por meio de um componente separado (no meu caso Validate)
Agora, se a validação tiver MESMO de ocorrer na Model, não convém usar __set(), senão uma lista enorme de condicionais deveria compor tal método para, baseado no valor do parâmetro (já que não há um tipo "CPF"), validar ou não.
E isso além der trazer uma tamanha repetição de código, indo contra os princípios do D.R.Y., ao meu ver, também viola a O.C.P. da classe e gera dependência, pois a Model teria de conhecer todos os campos que a compõe.
Nesse caso, acho o que o mais adequado seria um usar ambos, __set() para quem não precissa ser validado e um setter para quem precisar.
>
Mas agora vem um dilema, o que é melhor, criar exceptions para tudo que pode ser inserido pelo método mágico ou apenas criar um método com sua devida exception?
dae vem a engenharia de software, o planejamento...todo o planejamento influencia na programacao...nao adianta fazer um programa sem prever o q o usuario pode ou nao fazer...sempre tem akele usuario q se acha experto e sai testando as coisas pra mostrar q sabe mais q a TI...você nao sabe o nivel de instrucao da pessoa q vai usar o seu sistema, por isso documente, vai fazer manutencao documente...se o cara fez m***** ele vai ter q ler a documentacao...
vai de opinião muita gente ainda prefere usar os métodos mágicos mais na minha humilde opinião que não gosto de trabalhar então não me aprofundei muito é que esses métodos demoram para carregar e fazer o que tem que ser feito por utilizar muito recursos o que não acontece em uma estrutura que não se usa esses métodos sendo que essa estrutura foi escrita de maneira correta seguindo varias regras e com um padrão para programar