Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Lucas Peperaio

Avaliação de Classe PHP

Recommended Posts

Olá, sou programador PHP e estou me aprofundando no estudo da orientação a objetos, pois pretendo estudar Java futuramente. Tenho desenvolvido em meu dia-a-dia algumas classes, pois trabalho com outros 2 programadores, ajudando assim a manter um padrão entre nós.

 

Esta é uma classe que eu fiz para criação de thumbs com crop automático, com imagens em landscape, portrait ou square. Funciona da mesma forma que o Wordpress, pois cria as thumbs sem distorcê-las. Gostaria que avaliassem-a segundo os padrões do OO.

 

Este é o link do projeto:

http://projetos.lucaspeperaio.com.br/classe-thumb-php-crop-centralizado/

 

Obrigado a todos

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bom dia,

 

Curti demais essa classe hein... rsrsrs

 

No meu ponto de vista atende os padrões OO sim!!!

 

Ps.: Inclusive estou querendo pegar um trecho dela. Tenho sua autorização??? hehehe

Vou dar uma melhorada na que eu fiz!

 

Abraços

Atenciosamente

Uerlen Santos

Compartilhar este post


Link para o post
Compartilhar em outros sites

Sua classe viola o princípio da responsabilidade única. Ela manipula sistema de arquivos, cria resources, manipula imagens e também a saída para o navegador.

Além disso, existem propriedades públicas. Nada impede um programador desatento de fazer:

$thumb->jpegQuality = 200;

Experimente fazer isso e veja o resultado da imagem.

 

Eu não consegui compreender a diferença entre proccess() e makeThumb() numa leitura dinâmica.

 

Cabe uma boa refatorada aí... No mínimo 3 classes diferentes, uma para lidar com o sistema de arquivos, uma para lidar com a imagem em memória e outra para lidar com os formatos de saída.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Não sei se estou paranoico mas do meu ponto de vista trabalhar com pastas devia ser uma coisa diferente de gerar a thumb, me corrijam se eu estiver errado.

 

No Hangout de OO que participei foi muito citado a responsanbilidade única que é o que o Objeto deve fazer, no seu objetivo devia apenas gerar um thumb e nada mais enquanto pegar pastas setar pastas poderiam ser outro objeto pois ainda ganharia na flexibilidade a ponto de precisar pegar outra pasta e então não "recriar" a função.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Pontos relativos:

 

1. Image pode ser uma classe separada de Thumb, talvez um nome mais sugestivo, ThumbUtil, criando uma associação de agregação;

2. O encapsulamento da sua classe não esta completo, isto pode causar vários erros inexperados;

3. Seu método makeThumb ficou muito extenso, ruim para teste unitário;

4. Seu bloco try ... catch no método makeThumb esta muito extenso e nenhuma exceção é "levantada" apropriadamente;

5. Há problemas de lógica, entendo que showBrowser e forceDownload podem ser métodos, além de outros. Isto já começa a granular seu método makeThumb e resolver parcialmente os itens 3 e 4;

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bom dia,

 

Curti demais essa classe hein... rsrsrs

 

No meu ponto de vista atende os padrões OO sim!!!

 

Ps.: Inclusive estou querendo pegar um trecho dela. Tenho sua autorização??? hehehe

Vou dar uma melhorada na que eu fiz!

 

Abraços

Atenciosamente

Uerlen Santos

 

Tem sim, pode pegar. Para desenvolver esta classe eu estudei outras classes de thumb, fique a vontade, é open-source.

 

 

Sua classe viola o princípio da responsabilidade única. Ela manipula sistema de arquivos, cria resources, manipula imagens e também a saída para o navegador.

Além disso, existem propriedades públicas. Nada impede um programador desatento de fazer:

$thumb->jpegQuality = 200;

Experimente fazer isso e veja o resultado da imagem.

 

Eu não consegui compreender a diferença entre proccess() e makeThumb() numa leitura dinâmica.

 

Cabe uma boa refatorada aí... No mínimo 3 classes diferentes, uma para lidar com o sistema de arquivos, uma para lidar com a imagem em memória e outra para lidar com os formatos de saída.

Muito obrigado pelo comentário Henrique, estou aprendendo a trabalhar com OO ainda. Eu fiz o teste com o jpegQuality = 200 mas não vi algo anormal, apesar de saber que isso é impossível de ser feito. Realmente faltou essa validação.

 

Process() é o método que processa o Array de thumbs que pode ser passado para a classe. É possível criar múltiplas thumbs com diferentes tamanhos, umas com crop e outras sem o crop. Também é possível criar thumbs proporcionais, ou seja, passar só a largura e fazer a altura proporcional. É isso que ela faz, ajusta o tamanho ideal e passa para a MakeThumb criar a thumb

 

MakeThumb() é o método que cria a thumb em si, detectando o tipo da imagem, criando a thumb com ou sem o crop automático. Também é possível forçar o download da imagem, salvar numa pasta, colocar um sufixo (imagem-250x250), ou mostrar a imagem no navegador.

 

Estou procurando algum material simples sobre OO para estudo, tem alguma recomendação?

 

 

Não sei se estou paranoico mas do meu ponto de vista trabalhar com pastas devia ser uma coisa diferente de gerar a thumb, me corrijam se eu estiver errado.

 

No Hangout de OO que participei foi muito citado a responsanbilidade única que é o que o Objeto deve fazer, no seu objetivo devia apenas gerar um thumb e nada mais enquanto pegar pastas setar pastas poderiam ser outro objeto pois ainda ganharia na flexibilidade a ponto de precisar pegar outra pasta e então não "recriar" a função.

 

Obrigado Vinicius, olhando pelo seu ponto de vista, a MakeThumb fica recriando as funções a cada thumb processada, e isso com certeza deve consumir mais memória e tempo de processamento. Vou usar as suas dicas para melhorá-la.

 

 

Pontos relativos:

 

1. Image pode ser uma classe separada de Thumb, talvez um nome mais sugestivo, ThumbUtil, criando uma associação de agregação;

2. O encapsulamento da sua classe não esta completo, isto pode causar vários erros inexperados;

3. Seu método makeThumb ficou muito extenso, ruim para teste unitário;

4. Seu bloco try ... catch no método makeThumb esta muito extenso e nenhuma exceção é "levantada" apropriadamente;

5. Há problemas de lógica, entendo que showBrowser e forceDownload podem ser métodos, além de outros. Isto já começa a granular seu método makeThumb e resolver parcialmente os itens 3 e 4;

 

1. Obrigado pela sugestão

2. Desculpe minha ignorância, mas poderia citar um erro inesperado? Sou aprendiz em OO :P

3. Ficou mesmo e com muita responsabilidade, fazendo coisas distintas como ler a imagem, criar um resource, cropar a thumb, enviar para o navegador. Como os outros participantes disseram, preciso separar estas funções em outras classes.

4. Verdade, faltou o Throw New Exception em alguns trechos ali.. Seria isto?

5. Não entendi rs

 

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

1. Obrigado pela sugestão

2. Desculpe minha ignorância, mas poderia citar um erro inesperado? Sou aprendiz em OO :P

3. Ficou mesmo e com muita responsabilidade, fazendo coisas distintas como ler a imagem, criar um resource, cropar a thumb, enviar para o navegador. Como os outros participantes disseram, preciso separar estas funções em outras classes.

4. Verdade, faltou o Throw New Exception em alguns trechos ali.. Seria isto?

5. Não entendi rs

 

2. Pegando o gancho do Henrique:

$thumb->jpegQuality = 'qualidade normal que todo thumb jpeg deve ter';

Isto causa um erro "inesperado", pura e simplesmente pq não há tratamento de entrada.

 

4. Isso mesmo.

 

5. Isto faz parte de um contexto maior, que esta relacionado com a questão da responsabilidade. Invez de fazer testes, você pode definir os métodos para executar as tarefas especificas invez de fazer testes se isso e aquilo e ir dando saidas. Mas acho que esta explicação é irrelevante agora, você já entendeu o item 3 com as ponderações do Henrique.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Olá novamente.

Refatorei o meu código-fonte, incluindo duas novas classes, a browser() responsável por manipular o envio para o navegador e a image(), responsável por acessar o sistema de arquivos. Manti a classe thumb(), deixando-a responsável por criar o resource e criar a thumb.

 

Poderiam dar uma olhada novamente?

http://projetos.lucaspeperaio.com.br/classe-thumb-php-crop-centralizado/

 

Valeu grin.gif

Compartilhar este post


Link para o post
Compartilhar em outros sites

Hmmmm... não... Ficou pior :P...

 

Você está usando herança onde ela não cabe... É normal isso enquanto estamos aprendendo OO, eu até hoje me confundo...

 

Sugestão de separação de responsabilidades:

 

1 - Verificar se a imagem existe no sistema de arquivos e retorná-la já como todas as suas propriedades (nome, extensão, mime, largura, altura)

2 - Fazer alocação de um recurso de imagem criando uma imagem nova ou carregando a imagem que é obtida pelo item 1

3 - Fazer a manipulação de Imagens

4 - Fazer o output da imagem

 

Ou seja, no mínimo umas 4 classes aí...

 

Pense em algo do tipo:

$image = new ImageLoader('/endereco/da/imagem.jpg'); // Isso já vai obter todas as informações possíveis sobre a imagem
$allocator = new ImageResourceAllocator($image); // Isso irá criar resources GD para serem manipulados
$handler = new ImageHandler();
$thumb = $handler->resize($allocator, $width = 200, $height = 120, $quality = 60); // Isso irá retornar um novo ImageResourceAllocator

$output = new ImageOutputFileSystem();
$output->do($thumb, '/endereco/para/o/thumb.jpg'); // salva uma imagem JPEG no sistema de arquivos
$output->do($thumb, 'endereco/para/o/thumb.png'); // salva uma imagem JPEG no sistema de arquivos
// Note que você só precisa mudar a extensão e o método cuidará para que a imagem seja salva no formato correto
// ou...
$output = new ImageOutputBrowser();
$output->do($thumb, 'jpeg'); // Mostra uma imagem JPEG no navegador
$ouput->do($thumb, 'png'); // Mostra uma imagem PNG no navegador

 

Detalhe: NÃO HÁ NENHUMA HERANÇA nessa estrutura. Você pode até definir uma interface para as classes de output, mas não tem herança...

Compartilhar este post


Link para o post
Compartilhar em outros sites

1 - Verificar se a imagem existe no sistema de arquivos e retorná-la já como todas as suas propriedades (nome, extensão, mime, largura, altura)

2 - Fazer alocação de um recurso de imagem criando uma imagem nova ou carregando a imagem que é obtida pelo item 1

 

Eu transferiria um pouco das responsabilidades da 1 para 2.

 

Veja, se uma classe apenas acessar o sistema de arquivos ela será reutilizável sempre que desejarmos tal funcionalidade. Seja para obter uma imagem, um PDF, um vídeo, enfim.

 

Se essa mesma classe procura propriedades como largura e altura, estas propriedades podem não ser relevantes quando a nossa classe de SO lida com documentos de texto, por exemplo.

 

Uma vez que 2 aloca o recurso da imagem, somente depois que 2 faz isso é que se torna possível pegar as medidas/propriedades do recurso. Para que isso aconteça em 1, seria necessário o uso dos métodos de manipulação de imagem, amarrando a responsabilidade de 1 às imagens e perdendo flexibilidade. Obviamente, não é isso que queremos.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Acho válida a análise, Evandro...

Mas pensando em reutilização, que funcionalidades haveriam em comum para uma classe que lê um PDF e uma Imagem do filesystem, por exemplo?

 

Entretanto, concordo, a obtenção dos dados da imagem que vão além do nome, cabem melhor na responsabilidade #2...

Compartilhar este post


Link para o post
Compartilhar em outros sites

Olá, estou estudando tudo o que foi dito, realmente os conceitos apresentados são um pouco confusos para mim, que estou aprendendo por conta própria. Obrigado a todos que me ajudaram até agora

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bom, eu usaria um Factory para criar um objeto responsável por manipular um determinado recurso de imagem.

Dessa forma, ele implementaria ImageResource que exige os métodos createResource e output.

 

Assim você não iria precisar de fazer condicionais através do mime-type a cada vez que for usar create ou output, usaria apenas para achar qual recurso irá criar.

 

Até ai temos.

<?php

   interface ImageResource {

       // [ ... ]

   }

   class ImageResourceJPEG implements ImageResource { 

       // ...

   }

   class ImageResourcePNG implements ImageResource { 

       // ...

   }

   // ...

 

Então, sua fabrica iria saber quais desses objetos é o adequado para tratar determinado tipo de imagem de acordo com o arquivo dado.

A representação do arquivo você pode fazer com uma entidade.

 

O padrão Command é interessante nesse caso porque ele vai declarar uma interface para executar uma operação qualquer na Imagem, por exemplo um Resize ... então o seu ImageHandler seria o Invoker desses comandos, já que ImageHandler vai esperar um ImageResource para executar uma operação qualquer.

 

Acho que é isso, e cuidado com o SRP.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Mas pensando em reutilização, que funcionalidades haveriam em comum para uma classe que lê um PDF e uma Imagem do filesystem, por exemplo?

 

OCR???

 

Olá, estou estudando tudo o que foi dito, realmente os conceitos apresentados são um pouco confusos para mim, que estou aprendendo por conta própria. Obrigado a todos que me ajudaram até agora

 

Para saber se cabe ou não herança nas suas classes, pergunte a ela:

 

Classe B, você é uma Classe A ou você usa uma Classe A???

 

Exemplo clássico de quem começa a programar PHP em OO:

 

<?php

class Usuario extends DB
{...}


$fulano = new Usuario('mysql:host=localhost;dbname=sistema', 'sysdba', 'masterkey');

 

Quando falamos de herança, se B herda de A, então B é um A.

 

No excerto acima, estamos dizendo que Usuário é um DB o que, certamente, é incorreto.

 

Reflita, se estou criando um(a instância de) usuário, porque raios eu passo configurações de banco de dados????

 

Se eu preciso criar um usuário, deveria passar os parâmetros pertinentes a ele:

class Usuario
{
   public function __construct($nome, $sexo, $nascimento)
   {...}
}

$fulano = new Usuario('Fulano', 'Masculino', 'Ontem');
// A refatoração fica por sua conta

 

Bem mais claro, não?? Código autodescritivo é uma coisa linda que deveria correr no sangue do programador!

 

Mas, como eu vou salvar essa bagaça no DB???

 

Duas aproximações que eu considero válidas:

$fulano->saveInto($instancia_do_banco_de_dados);

 

ou

 

$instancia_do_banco_de_dados->save($fulano);

 

Tenho uma leve preferência pela segunda forma. A primeira é uma clara demonstração de Usuário que usa um banco de dados, sendo que a segunda é um banco de dados que usa um usuário.

 

Tenha isso em mente, existe herança quando B é um A

 

José da Silva tem um filho, João.

 

João é um herdeiro de José. João é um da Silva

Compartilhar este post


Link para o post
Compartilhar em outros sites

Vamos ver o que mais...

 

public function setInfoImage( $infoImage ) {
   $this->infoImage = getimagesize( $infoImage );
}

Que usuário em sã consciência vai invocar esse método depois de ter a imagem pronta, caso no qual o path de saída tenha sido criado.

 

Ou então, quem invocar esse método sobre uma imagem qualquer, esperaria ver alguma coisa não? Por que cargas d'água ele deveria invocar esse método para depois invocar o getInfoImage()?

 

Resumindo... Se a informação constrói parte do objeto, ela pertence ao construtor. :thumbsup:

 

O Andrey já falou sobre os formatos suportados pela classe no post #14. Creio eu que só faltou mencionar que, salvo engano, o que você fez viola os princípios da O.C.P (Open Closed Principle) onde para suportar um novo formato, você deveria editar a classe Image.

 

Já falaram do FileSystem que deveria ser à parte...

 

Browser não é uma Image e nem Thumb é um Browser, mas o Prog já teu o caminho das pedras sobre isso no post #10

 

Thumb::imageCreate() repete Browser::output(), coisa que não aconteceria se Thumb recebesse o objeto Image para trabalhar.

 

No mais, eu acho que faltou também você separar o modo como as operações são realizadas. Sua classe trabalha com a GD, mas e se um dia a GD for descontinuada e com sucessivos upgrades do PHP ela se tornar obsoleta?

 

Você vai mesmo criar uma segunda versão ou pior, editar todas as classes para suportar ImageMagick

Compartilhar este post


Link para o post
Compartilhar em outros sites

Sim, sobre o setInfoImage(), eu havia feito público para tornar disponível para as classes filhas, browser() e thumb(). POO é mais difícil que eu imaginava, muitas regras e conceitos, acho que vou levar mais tempo aprendendo tudo ainda. Sobre o imagemagick, confesso que nunca ouvi falar, vou dar uma pesquisada melhor.

Evandro Oliveira, sua explicação me deu uma luz no fim do túnel rs.. Browser não é uma imagem, portanto ele não deveria herdar suas características.

Pelo o que eu estou vendo terei umas 5 ou 6 classes, talvez uma ou duas interfaces.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Não possuo muito a agregar (o pessoal veio com sede, e fome, ao tópico e não me deixaram nem farelo), além de fator motivacional (o qual eu acho importante).

 

POO é mais difícil que eu imaginava, muitas regras e conceitos, acho que vou levar mais tempo aprendendo tudo ainda.

Tempo é uma chave importante. Não diria que é difícil. Sim é difícil. Mas, mais que difícil, é trabalhoso. Diferente de algo que é dado pronto, se você não suar a camisa, não ler, reler, transcrever, traduzir, parafrasear e até "plagiar" (tudo metaforicamente falando), usar o que é bom de outros programadores (com os devidos créditos é claro). Você não vai aprender. O mundo OO é vasto,

 

Isso tudo me lembra o prefácio de um dos livros do Robert UncleBob Martin, se não me engano é o Clean Code. Onde ele fala para suar a camisa até o código ser parte de você, até estar no seu sangue.

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.