Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
Olá Pessoal,
Fiquei alguns dias sem postar pois estava reescrevendo o conteúdo, como daqui para frente algumas coisas ficam mesmo mais complexas, resolvi simplificar os códigos para que o entendimento seja melhor.
Da última vez, falamos sobre um design pattern chamado Iterator, sobre as interfaces Iterator e IteratorAggregate, hoje vamos começar a demonstrar alguns iteratores da SPL, o primeiro será o FilterIterator.
Como o próprio nome sugere FilterIterator é um iterator com o objetivo de filtrar dados de um conjunto de elementos, imaginem a seguinte situação:
$lista = array( 10 , 30 , 2 , 9 , 7 , 0 , 1 , 8 , 6 , 10 );
Temos nessa lista, vários números entre pares e impares. Muitas vezes estamos diante de situações como essa, onde possuímos diversos valores, mas somente alguns desses nos interessam como, por exemplo, apenas os pares.
Para nossa felicidade, a SPL nos oferece a FilterIterator, uma classe abstrata que servirá como base para criação de filtros reutilizáveis, por exemplo, vamos imaginar que queremos apenas os números pares daquela lista:
EvenFilterIterator.php
class EvenFilterIterator extends FilterIterator {
public function accept(){
$item = $this->getInnerIterator()->current();
return ( $item % 2 ) == 0;
}
}
Como é notório, nossa classe EvenFilterIterator possui apenas 1 método, esse método é chamado automaticamente pela FilterIterator quando estamos percorrendo os elementos de uma lista, vamos ver como funciona:
<?php
$lista = array( 10 , 30 , 2 , 9 , 7 , 0 , 1 , 8 , 6 , 10 );
foreach ( new EvenFilterIterator( new ArrayIterator( $lista ) ) as $item ){
var_dump( $item );
}
A saída será:
int(10)int(30) int(2) int(0) int(8) int(6) int(10)
Vejam só, temos um filtro para números pares, totalmente reutilizável, agora, imaginem que tenhamos na nossa lista, vários tipos de elementos:
$lista = array( 'Teste' , 10 , true , null , 'email@teste.com' , 9 , 7 , 'João Batista Neto' , false , 12.75 , 'fulano@dominio.com' , 10 );
E, se quisermos apenas as strings dessa lista ?
StringFilterIterator.php
class StringFilterIterator extends FilterIterator {
public function accept(){
return is_string( $this->getInnerIterator()->current() );
}
}
Pronto, temos um filtro para strings reutilizável, vamos ver o resultado:
<?php
$lista = array( 'Teste' , 10 , true , null , 'email@teste.com' , 9 , 7 , 'João Batista Neto' , false , 12.75 , 'fulano@dominio.com' , 10 );
foreach ( new StringFilterIterator( new ArrayIterator( $lista ) ) as $item ){
var_dump( $item );
}
A saída:
string(5) "Teste"string(15) "email@teste.com" string(18) "João Batista Neto" string(18) "fulano@dominio.com"
Mas, todas as strings também não nos interessa, queremos apenas o que é email. Simples:
EmailFilterIterator.php
class EmailFilterIterator extends FilterIterator {
public function accept(){
return filter_var( $this->getInnerIterator()->current() , FILTER_VALIDATE_EMAIL );
}
}
Pronto, agora é só iterar nossa lista:
<?php
$lista = array( 'Teste' , 10 , true , null , 'email@teste.com' , 9 , 7 , 'João Batista Neto' , false , 12.75 , 'fulano@dominio.com' , 10 );
foreach ( new EmailFilterIterator( new StringFilterIterator( new ArrayIterator( $lista ) ) ) as $item ){
var_dump( $item );
}
Saída:
string(15) "email@teste.com"string(18) "fulano@dominio.com"
Bom, funciona assim:
1. A FilterIterator é uma classe abstrata que deixa a responsabilidade da definição do método accept() para que implementemos.
2. O método construtor da FilterIterator precisa necessariamente receber um Iterator, por isso utilizamos ArrayIterator para nossa array.
3. Quando passamos um Iterator qualquer para o construtor, esse Iterator fica encapsulado na FilterIterator, para que possamos acessá-lo, precisamos usar o método getInnetIterator(), que faz justamente isso, retorna o Iterator que passamos para o construtor.
4. O método accept() é chamado a cada volta do Iterator, se retornar TRUE então o valor é válido, caso contrário o valor é ignorado e o próximo item do InnerIterator é testado.
Com isso, podemos criar vários tipos de filtros reutilizáveis e, para utilizá-los, basta encadear os filtros que queremos para, em poucas linhas, tenhamos o resultado esperado.
Bom, por hora é só, no próximo tópico da série PHP Orientado a Objetos, continuaremos falando sobre a SPL.
/applications/core/interface/imageproxy/imageproxy.php?img=http://forum.imasters.com.br/public/style_emoticons/default/wink.gif&key=0566fd943552bcff9cb1b879403ca34b5ff8f67befaac7fe4648006e9f764689" alt="Imagem Postada" class="bbc_emoticon">
Índice /applications/core/interface/imageproxy/imageproxy.php?img=http://forum.imasters.com.br/public/style_emoticons/default/seta.gif&key=e2d72b30771339c36df1f88688ecc571784dab60a19e2c7c2ff398c277802ac0" alt="Imagem Postada" class="bbc_emoticon">
hehe muito bom joao ! parabas novamente
boa iniciativa de explica todos os principais componentes da SPL pois ja que php nao é orientado a objto mas sim tem suporte a esta esse recurso é muito importante =]
valww
Olha, esse ficou bem fácil de entender.
Mas no exemplo da EmailFilterIterator faz-se mesmo necessário passar o ArrayIterator como argumento de StringIterator pra só então alcançar o iterator principal, de e-mail?
Porque um e-mail já é uma string, não dá pra ser de outro tipo e mesmo que numa possibilidade o for, a filter_var() já excluiria essas aberrações. Certo?
P.S.: Eu testei a proposição acima ^^
O método construtor da FilterIterator requer um Iterator para ser o InnerIterator, então, se você for iterar uma matriz (array) comum você precisará sim, utilizar um ArrayIterator (ou qualquer iterator que aceite uma matriz).
Quanto a questão de passar para o construtor do EmailIFilterterator um StringFilterIterator, realmente não é necessário, eu o fiz para demonstrar o encadeamento (chain), mas sim, a filter_var() faz o trabalho sozinha nesse caso específico.
Sucinto, claro e objetivo. Parabéns e obrigado.
Mais uma vez, acompanhando os seus textos, João, consigo captar muito bem o conteúdo.
Parabéns pela dicção e maneira de ensino, e principalmente pela iniciativa.
Aguardando os próximos.
Muito bom João.
Tenho uma pergunta =D
Tipo, vejo que o código pode ficar bem grande:
new EmailFilterIterator( new StringFilterIterator( new ArrayIterator( $lista ) )Tem algum problema em "diminuir" este código? Veja bem... TODO email, será uma string, e todos devem interagir com um arrayiterator, então, porque especificar eles se SEMPRE será assim?Não poderiamos criar uma função/classe para facilitar as coias, algo como:
foreach(SimpleEmailFilter( $lista ) as $item )...Deste modo, a classe SimpleEmailFilter já "chamaria" EmailFilterIterator, StringFilterIterator e ArrayIterator, e poupamos algum comprimento no código e ainda podemos continuar utilizando os filtros ainda disponiveis se necessários.Tem algum problema nessa abordagem?
>
Tem algum problema nessa abordagem?
Claro que não tem problema algum nessa abordagem, veja que eu já havia dito isso anteriormente para o Imaggens, fiz dessa forma apenas para demonstrar o encadeamento, mas é completamente aceitável a implementação direta.
Ahh... vlw =)
Isso que dá não prestar atenção nos outros posts xD
Tenho uma dúvida que se refere a este tópico.
Eu implementei a solução que postei utilizando o FilterIterator, e ficou dessa maneira:
class RemoveItemFilterIterator extends FilterIterator {
public function accept() {
return substr( $this->getInnerIterator()->current(), 0, 4 ) == 'cur_';
}
}
$array = array( 'sar_3', 'cur_40', 'cur_41', 'cur_115', 'dar_56', 'aar_57' );
$teste = new RemoveItemFilterIterator( new ArrayIterator( $array ) );
A minha duvida é: como que eu filtro esse array e tenho como retorno esse mesmo array filtrado. Se ele retornasse um objeto, eu o "converteria" para array com um simples (array), porém nem esse objeto estou conseguindo obter.
Eu poderia muito bem fazer um foreach e jogar esses valores filtrados dentro de um novo array, mas sei lá, não teria algo mais prático :D?
Abraços.
Mas, para que você você precisa disso ?
Bacana demais.
Muito bom João. Não sabia dessa, alias não sabia de várias coisas da SPL. Vou começar a olhar ela com mais carinho hehe, tem coisa muito boa lá.
Claps!