Desenvolvimento - PHP
Orientação à Objetos em PHP – Métodos e atributos estáticos
Certo dia na faculdade estava vendo o código de um colega que está aprendendo PHP e comecei a discutir com ele algumas melhorias, o resultado final foi tão satisfatório e diferente do original que resolvi criar um post pra mostrar como o código evoluiu.
por Thiago BelemO código original – Orientado à objetos ou PHP estruturado?
O código original já estava dentro de uma classe, mas não faria diferença nenhuma se fosse PHP estruturado… não lembro exatamente o nome dos métodos/variáveis, mas o restante está igualzinho:
class cFileType { function fImage($type) { switch($type) { case 'jpg': $bool = true; break; case 'png': $bool = true; break; case 'gif': $bool = true; break; default: $bool = false; break; } return $bool; } }
A primeira mudança foi trocar esse switch, que não está fazendo nada além de definir o valor da variável $bool como true ou false se o $type for um dos valores válidos (jpg, png ou gif)… Nada melhor então do que usar a função in_array():
class cFileType { function fImage($type) { return in_array($type, array('jpg', 'png', 'gif')); } }
WOW! Reduzimos de 21 para 7 linhas… mas ainda assim, se fosse estruturado não teria diferença nenhuma.
Meu amigo me disse que essa classe seria para verificar os tipos de arquivos (extensões), por exemplo “se é uma imagem” ou “se é um doc”… Então criamos outro método para verificar DOCs:
class cFileType { function fImage($type) { return in_array($type, array('jpg', 'png', 'gif')); } function fDoc($type) { return in_array($type, array('doc', 'docx')); } }
Atributos, melhor tê-los
O código está melhorando, mas ainda assim tem algo errado… não é responsabilidade dos métodos fImage e fDoc saber a lista de extensões válidas… isso não deveria pertencer à classe como um todo e poder ser reutilizado?
class cFileType { public $image = array('jpg', 'png', 'gif'); public $doc = array('doc', 'docx'); function fImage($type) { return in_array($type, $this->image); } function fDoc($type) { return in_array($type, $this->doc); } }
Atributos e métodos estáticos
Agora sim está parecendo uma classe normal, com atributos e métodos… Aí percebi que de orientada à OBJETOS essa classe não tem nada! Não estamos trabalhando com objetos.. O uso atual dessa classe seria assim:
$cFileType = new cFileType(); if ($cFileType->fImage('jpg')) { // É uma imagem válida }
Eu não trabalho o objeto $cFileType, apenas instancio e utilizo um único modo… então vamos economizar um pouco de memória, transformando os métodos em métodos estáticos:
class cFileType { public static $image = array('jpg', 'png', 'gif'); public static $doc = array('doc', 'docx'); static function fImage($type) { return in_array($type, self::$image); } static function fDoc($type) { return in_array($type, self::$doc); } }
E agora a utilização ficou um pouco mais simples:
if (cFileType::fImage('jpg')) { // É uma imagem válida }
Sendo que você ainda pode usar o cFileType::image (pra ter uma lista de imagens válidas) em qualquer parte da sua aplicação sem instanciar a classe.
Reutilização de código
Segundo a abordagem DRY , não devemos nos repetir… Por isso aquele in_array()começou a me incomodar… Vai que você está verificando 30 tipos diferentes de arquivos, todos os métodos fazendo exatamente a mesma coisa… mas aí você decide mudar o in_array() pra algo mais eficiente ou aceitar até o caminho absoluto de um arquivo… vai mudar em 30 métodos na mão?
A responsabilidade de verificar se o valor $type tá dentro de uma “lista” válida não é dos métodos fImage e fDoc.. então vamos delegar:
class cFileType { public static $image = array('jpg', 'png', 'gif'); public static $doc = array('doc', 'docx'); static function fType($type, $list) { return in_array($type, $list); } static function fImage($type) { return self::fType($type, self::$image); } static function fDoc($type) { return self::fType($type, self::$doc); } }
Agora se precisarmos mudar essa lógica de verificar se o $type tá dentro de uma “lista” válida, só vamos precisar mudar em um lugar só.
cFileType? fType? fImage? O resultado final
Temos que concordar que os nomes de classe e métodos escolhidos pelo meu amigo não são os mais intuitos… Então como uma modificação final, sugiro a seguinte classe devidamente renomeada:
class FileType { public static $image = array('jpg', 'png', 'gif'); public static $doc = array('doc', 'docx'); public static function isTypeInList($type, $list) { return in_array($type, $list); } public static function isImage($type) { return self::isTypeInList($type, self::$image); } public static function isDoc($type) { return self::isTypeInList($type, self::$doc); } }
Com uma utilização bem simples e intuitiva:
if (FileType::isImage('jpg')) { // É uma imagem válida }
Espero que tenham gostado!
Pra quem quiser ver o código completo da classe final, com os métodos comentados:https://gist.github.com/1338259
Artigo originalmente publicado por Thiago Belem: Orientação à Objetos - Métodos e atributos estáticos