falcao544 11 Denunciar post Postado Maio 12, 2012 Olá pessoal, eu estava lendo um livro sobre PHP OO, e vi que um método pode ser declarado como "asbtract"! Então, a minha dúvida é a seguinte, em que situação eu usaria isso? Obrigado! EDIT: Aproveitando o tópico, eu queria saber se assim que eu crio um objeto de uma classe que tem o método __construct, se o __construct vai ser executado imediatamente, mesmo que eu tenha outros métodos antes dele! Obrigado! Compartilhar este post Link para o post Compartilhar em outros sites
shini 318 Denunciar post Postado Maio 12, 2012 metodo abstrato ser para você definir uma assinatura unica. e as classes q herdaram esse metodo teram um comportamento especifico. Compartilhar este post Link para o post Compartilhar em outros sites
falcao544 11 Denunciar post Postado Maio 12, 2012 Obrigado, mas você pode ser mais específico? Eu to aprendendo PHP OO ainda! Obrigado! Compartilhar este post Link para o post Compartilhar em outros sites
Alaucho 5 Denunciar post Postado Maio 12, 2012 A ideia de um método abstrato, é você declará-lo, informando que as classes filhas daquela classe onde se encontra o método, devem utilizá-lo, com o comportamento específico. Lembrando que quando se declara um método como abstrato, obrigatoriamente a classe também deve ser declarada como abstrata. Porém, o inverso não é obrigatório. Ou seja, eu posso declarar uma classe como abstrata, mas não ter nenhum método abstrato. Outro detalhe, é que ao declarar o método abstrato, o mesmo será apenas uma assinatura, sem ter a estrutura implementada, cabendo isto as classes filhas da forma necessária. Seria algo mais ou menos assim (um exemplo bem simples): <? abstract class RecursoHumano { // ... propriedades e métodos da classe abstract function salario() {} } class Professor extends RecursoHumano { public function salario() { // ... estrutura da função salario() para a classe Pessoa } } class Funcionario extends RecursoHumano { public function salario() { // ... estrutura da função salario() para a classe Funcionario } } ?> Bom, não sei se ficou bem claro, mas como deu pra ver, foi declarada uma classe abstrata com um método também abstrato, sem nada implementado. A implementação, coube as classes filhas, que implementam o que quiserem dentro desses métodos. Caso uma classe filha não utilize o método, será retornado um erro. Vale lembrar também que uma classe abstrata não pode ser instanciada. Acho que eras isso. Abs Compartilhar este post Link para o post Compartilhar em outros sites
Henrique Barcelos 290 Denunciar post Postado Maio 12, 2012 Bom, para entender a necessidade de métodos abstratos, primeiro você precisa entender o que é polimorfismo Na programação orientada a objetos, o polimorfismo permite que referências de tipos de classes mais abstratas representem o comportamento das classes concretas que referenciam. Assim, é possível tratar vários tipos de maneira homogênea (através da interface do tipo mais abstrato). O termo polimorfismo é originário do grego e significa "muitas formas" (poli = muitas, morphos = formas). O polimorfismo é caracterizado quando duas ou mais classes distintas tem métodos de mesmo nome, de forma que uma função possa utilizar um objeto de qualquer uma das classes polimórficas, sem necessidade de tratar de forma diferenciada conforme a classe do objeto.[1] Uma das formas de implementar o polimorfismo é através de uma classe abstrata, cujos métodos são declarados mas não são definidos, e através de classes que herdam os métodos desta classe abstrata.[2] Um objeto é definido pelo que ele sabe (campos/propriedades) e pelo que ele faz (métodos/operações). Normalmente, não gostamos de compartilhar tudo o que sabemos com as outras pessoas, mas utilizamos nosso conhecimento para realizar tarefas. Da mesma forma acontece com os objetos. Entretanto, para realizar uma mesma tarefa, cada pessoa pode ter um meio COMPLETAMENTE diferente de fazê-lo, produzindo ao final resultados semelhantes. Imagine que você precisa escrever uma redação. Supondo que você é destro, utilizará sua mão direita que obedecerá comandos do seu cérebro para escrevê-la. Uma outra pessoa, canhota, utilizará sua mão esquerda e utilizará seu próprio cérebro. No final, o resultado é o mesmo: uma redação (mesmo que possam ter diferentes níveis de qualidade, ainda é uma redação). Perceba também que tanto você, quanto o outro redator são do mesmo "tipo" Pessoa. Agora vamos trazer isso para o contexto de programação. Muitas vezes, possuímos um conjunto de objetos/"entidades" (note as aspas) que realizam tarefas muito parecidas, e, por isso, estão relacionadas entre si através de herança. Desejamos que tal conjunto realize uma determinada tarefa comum, esperando um certo retorno. Entretanto, não interessa os meios que o objeto utilizará para nos fornecer tal retorno. Mas como forçar esse conjunto de objetos a realizar tal operação de modo que eu possa solicitar sua execução em qualquer elemento desse conjunto, me garantindo um retorno correto? É aí que entram os métodos abstratos. Um método abstrato serve para declarar que uma operação é realizada por um certo objeto. O mais importante é que, qualquer classe que possua ao menos um método abstrato deve ser declarada como abstrada. Quando uma classe é abstrata, ela não pode ser instanciada. Suas funcionalidades são obtidas única e exclusivamente pela criação de classes concretas que dela derivam. Tais classes herdam os possíveis métodos já implementados pela classe-mãe e obrigatoriamente precisam implementar seus métodos abstratos. Caso isso não ocorra, um erro será acusado pelo interpretador do PHP.. Uma vez implementado aquele método abstrato, a classe derivada pode se utilizar de todos os meios que o seu conhecimento(propriedades/campos) e outras operações lhe permitem para realizar aquela função. Isso é polimorfismo! Seguindo o exemplo que dei acima, você teria algo como: abstract class Pessoa { protected $nome; protected $maoDireita = 'Mão Direita'; protected $maoEsquerda = 'Mão Esquerda'; public function getNome() { return $this->nome; } abstract public function escreverRedacao(); public function __construct($nome) { $this->nome = $nome; } } class Destro extends Pessoa { public function escreverRedacao() { echo "Escrevendo redação com a " . $this->maoDireita; } } class Canhoto extends Pessoa { public function escreverRedacao() { echo "Escrevendo redação com a " . $this->maoEsquerda; } } $pessoa = new Pessoa("Zé"); // Erro $voce = new Destro("falcao544"); $jimmy = new Canhoto("Jimmy Hendrix"); $voce->escreverRedacao(); // Mostra: Escrevendo redação com a Mão Direita $jimmy->escreverRedacao(); // Mostra: Escrevendo redação com a Mão Esquerda _________________________________________________________________________________________ Quanto a sua segunda pergunta, o construtor é chamado automaticamente assim que você cria o objeto (com o operador new). Não importa se você declara ele no começo ou no fim da classe, ele sempre será invocado primeiro. Compartilhar este post Link para o post Compartilhar em outros sites
Guilherme_90 33 Denunciar post Postado Maio 12, 2012 Sei que não tem nada haver com o assunto, mais é Jimi Hendrix! :lol: (brincadeiras a parte...). E gostei da resposta do Henrique, eu mesmo estava com certas dúvidas deste tipo. Este seu exemplo aplica-se também para interfaces? Compartilhar este post Link para o post Compartilhar em outros sites
Henrique Barcelos 290 Denunciar post Postado Maio 13, 2012 Eu não quis falar de interfaces no post pq se não ia ficar extenso demais e ninguém leria. Mas já que perguntou... Bom, algumas linguagens, como o PHP, o Java. Python e Ruby possuem também (embora o conceito seja um pouco diferente, não posso me aprofundar muito por que não conheço o suficiente dessas linguagens). Mas afinal, o que vem a ser uma interface? No mundo real, interface pode ser entendida como aquilo que separa dois meios distintos. Por exemplo, a interface entre nós e o espaço sideral é a atmosfera terrestre. Voltando ao nosso mundinho, uma interface é uma estrutura que representa o comportamento esperado de um dado objeto que a implemente. Em outras palavras, uma interface define o que um objeto deve fazer. E vou além, uma interface define somente O QUE o objeto deve fazer, mas não COMO fazê-lo. Do ponto de vista prático, um método de interface é praticamente igual a um método abstrato. A única diferença entre ambos é que um método de interface obrigatoriamente é public (pois representa a interface do objeto para o mundo exterior) enquanto que métodos abstratos também podem ser protected (mas não private. Por quê???). Quando um objeto diz implementar uma interface, ele assina um contrato no qual concorda implementar todos os métodos lá descritos, mas não de qualquer jeito, e sim de maneira coerente. No PHP, que é dinamicamente tipado, é muito fácil retornar uma string onde deveria-se retornar um inteiro. Em outras linguagens, como Java, isso não é possível, por isso, ao se programar em PHP precisamos ser mais cuidadosos para honrar as interfaces que os objetos implementam. Um exemplo bem simples de entender é a interface Serializable. Ela permite que um objeto seja convertido em uma versão textual do mesmo para ser armazenado em algum lugar e também um meio para criar um novo objeto a partir dessa representação. E quais objetos podem fazer isso? Qualquer um que eu deseje. Mesmo que eles não estejam relacionados entre si. Imagine que você tenha uma caixa onde você pode guardar 2 tipos de coisas: importantes e lixo. Você está de mudança para uma nova cidade e quer despachar sua caixa, entretanto, há um limite de peso, então você decide se livrar do "lixo" dentro dela antes de enviar. Ao chegar na sua nova cidade, você pegará somente as coisas importantes para colocar na sua nova caixa. <?php class Box implements Serializable { private $importantStuff = array(); private $trashStuff = array(); public function addImportant($thing) { $this->importantStuff[] = $thing; } public function addTrash($thing) { $this->trashStuff[] = $thing; } public function serialize() { return serialize($this->importantStuff); } public function unserialize($serial) { $this->importantStuff = unserialize($serial); } } $box = new Box(); $box->addImportant("Foo"); $box->addImportant("Bazzinga"); $box->addTrash("Blablabla"); $serial = $box->serialize(); echo 'Representação Serial: ' . $serial; $box2 = new Box(); $box2->unserialize($serial); var_dump($box); var_dump($box2); Saída: Representação Serial: a:2:{i:0;s:3:"Foo";i:1;s:8:"Bazzinga";} object(Box)#1 (2) { ["importantStuff":"Box":private]=> array(2) { [0]=> string(3) "Foo" [1]=> string(8) "Bazzinga" } ["trashStuff":"Box":private]=> array(1) { [0]=> string(9) "Blablabla" } } object(Box)#2 (2) { ["importantStuff":"Box":private]=> array(2) { [0]=> string(3) "Foo" [1]=> string(8) "Bazzinga" } ["trashStuff":"Box":private]=> array(0) { } } Note que estou utilizando a função nativa do PHP chamada serialize por simplicidade, mas eu poderia utilizar qualquer algoritmo para codificar o objeto em uma string, desde que ele me permita fazer o caminho reverso. Exemplo: public function serialize() { return join('###', $this->importantStuff); } public function unserialize($serial) { $this->importantStuff = explode('###', $serial); } Saída: Representação Serial: Foo###Bazzinga object(Box)#1 (2) { ["importantStuff":"Box":private]=> array(2) { [0]=> string(3) "Foo" [1]=> string(8) "Bazzinga" } ["trashStuff":"Box":private]=> array(1) { [0]=> string(9) "Blablabla" } } object(Box)#2 (2) { ["importantStuff":"Box":private]=> array(2) { [0]=> string(3) "Foo" [1]=> string(8) "Bazzinga" } ["trashStuff":"Box":private]=> array(0) { } } Deu pra sacar? Não importa COMO eu vou criar a representação textual, só me importa que eu GARANTO que irei criá-la. Uma outra dúvida bastante comum é: onde eu uso classes abstratas e onde eu uso interfaces? Não existe uma receita de bolo, mas eu costumo me guiar pela seguinte pergunta: É possível que essa funcionalidade seja requerida em vários objetos sem nenhuma relação entre sí? Ou ela é aplicável somente a um conjunto bem definido de classes que se relacionam por herança? Se a sua situação é a primeira, utilize interfaces, se é a segunda, utilize classes/métodos abstratos. Compartilhar este post Link para o post Compartilhar em outros sites
Guilherme_90 33 Denunciar post Postado Maio 13, 2012 Eu não quis falar de interfaces no post pq se não ia ficar extenso demais e ninguém leria. Engane-se. Quem realmente quer aprender, irá ler esse seu post quantas vezes forem necessárias. Bom, já li a primeira, certamente lerei mais vezes pra compreender ainda mais. Este tipo de informação, até o momento não encontrei em outro fórum, por isso este aqui é simplesmente f***! Obrigado por compartilhar. Compartilhar este post Link para o post Compartilhar em outros sites
Bruno Augusto 417 Denunciar post Postado Maio 13, 2012 A ideia de um método abstrato, é você declará-lo, informando que as classes filhas daquela classe onde se encontra o método, devem utilizá-lo, com o comportamento específico. Quase! As classes filhas devem implementar os métodos declarados na classe-pai provendo um um recurso esperado que, normalmente, a própria classe-pai vai utilizar: <?php abstract class Employee { protected $salary; public function __construct() { $this -> salary = $this -> defineSalary(); } public function getSalary() { return $this -> salary; } } class Teacher extends Employee { public function defineSalary() { return 1000; } } class Principal extends Employee { public function defineSalary() { return 2000; } } $teacher = new Teacher; $principal = new Principal; var_dump( $teacher -> getSalary(), $principal -> getSalary() ); // 1000 e 2000 Claro que esse não é o melhor exemplo, afinal, como o slário é parte do funcionário deveria fazer parte do construtor do objeto. abstract class Pessoa { protected $nome; protected $maoDireita = 'Mão Direita'; protected $maoEsquerda = 'Mão Esquerda'; public function getNome() { return $this->nome; } abstract public function escreverRedacao(); public function __construct($nome) { $this->nome = $nome; } } class Destro extends Pessoa { public function escreverRedacao() { echo "Escrevendo redação com a " . $this->maoDireita; } } class Destro extends Pessoa { public function escreverRedacao() { echo "Escrevendo redação com a " . $this->maoEsquerda; } } Um pequeno víciozinho de Ctrl+C, Ctrl+V. Você não defniu a classe Canhoto, só repetiu a Destro ^_^ Aproveitando o tópico, eu queria saber se assim que eu crio um objeto de uma classe que tem o método __construct, se o __construct vai ser executado imediatamente, mesmo que eu tenha outros métodos antes dele! Obrigado! Sim, a ordem dos fatores não altera o produto. Pelo menos não nesse caso. Compartilhar este post Link para o post Compartilhar em outros sites
Henrique Barcelos 290 Denunciar post Postado Maio 13, 2012 m pequeno víciozinho de Ctrl+C, Ctrl+V. Voc^Çe não defniu a classe Canhoto, só repetiu a Destro Verdade, valeu!!! Compartilhar este post Link para o post Compartilhar em outros sites
falcao544 11 Denunciar post Postado Maio 15, 2012 Desculpem a demora! Vou ler e re-ler tudo o que está escrito! Muito obrigado a todos! Os moderadores estão de parabéns, sempre dando uma aula! Obrigado! Se eu tiver alguma duvida depois, eu volto a postar! Boa noite! Compartilhar este post Link para o post Compartilhar em outros sites
FK. 0 Denunciar post Postado Maio 15, 2012 Eu vou tentar falar um pouco sobre parâmetros tipados, o que é muito útil quando usamos interfaces ou classes abstratas em conjunto com o polimorfismo. Imagine que temos um avião que irá voar para uma certa cidade. Nele, temos diversos passageiros que estão com pressa e precisam chegar rápido para essa cidade. Apenas com isso, podemos observar dois objetos envolvidos, Avião e Passageiro. Através destes, surgem muitos outros, como diversos modelos de avião, diversos tipos de passageiros, etc. Então num exemplo simples, imaginamos que esse avião já chegou em tal cidade, e precisamos que todos os passageiros desembarquem desse avião imediatamente: passageiro.php: class Passageiro { protected $nome; protected $tipo; public function subirNoAviao() { echo 'O(a) ' . $this->tipo . ' ' . $this->nome . ' subiu no avião. Está pronto(a) para a embarcação.'; } public function descerDoAviao() { echo 'O(a) ' . $this->tipo . ' ' . $this->nome . ' desceu do avião. Chegou na cidade.'; } } tripulante.php: require_once('passageiro.php'); class Tripulante extends Passageiro { public function __construct($nome, $tipo) { $this->nome = $nome; $this->tipo = $tipo; } } piloto.php require_once('passageiro.php'); class Piloto extends Passageiro { public function __construct($nome, $tipo) { $this->nome = $nome; $this->tipo = $tipo; } } aviao.php: interface IAviao { public function embarcar(); public function desembarcar(Passageiro $passageiros); public function voar(); } A747.php: require_once('aviao.php'); require_once('passageiro.php'); class A747 implements IAviao { // 747 private $name; private $tripulantes; public function __construct($name) { $this->name = $name; $tripulantes = array(); } public function setTripulante(Passageiro $passageiro) { $this->tripulantes[] = $passageiro; } public function embarcar() { foreach($this->tripulantes as $tripulante) echo $tripulante->subirNoAviao() . '<br />'; echo '<br />'; echo $this->voar() . '<br />'; } public function desembarcar() { echo 'O ' . $this->name . ' está desembarcando. Os passageiros precisam descer do avião imediatamente.' . '<br />'; echo '<br />'; foreach($this->tripulantes as $tripulante) echo $tripulante->descerDoAviao() . '<br />'; } public function voar() { echo 'O ' . $this->name . ' já está sobre embarcação. Por favor, apertem os cintos.' . '<br />'; echo 'Quem entrou, entrou. Quem não entrou, perdeu o voo.' . '<br />'; echo '<br />'; echo 'Voando...'; echo '<br />'; } } index.php: require_once('tripulante.php'); require_once('A747.php'); require_once('piloto.php'); $a747 = new A747('747'); $tripulantes = array('Fernando' => new Tripulante('Fernando', 'tripulante'), 'Camila' => new Tripulante('Camila', 'tripulante'), 'Gabriel' => new Piloto('Gabriel', 'piloto')); foreach($tripulantes as $key => $tripulante) { $a747->setTripulante($tripulantes[$key]); } echo $a747->embarcar($tripulantes); echo $a747->desembarcar($tripulantes); Saída: O(a) tripulante Fernando subiu no avião. Está pronto(a) para a embarcação. O(a) tripulante Camila subiu no avião. Está pronto(a) para a embarcação. O(a) piloto Gabriel subiu no avião. Está pronto(a) para a embarcação. O 747 já está sobre embarcação. Por favor, apertem os cintos. Quem entrou, entrou. Quem não entrou, perdeu o voo. Voando... O 747 está desembarcando. Os passageiros precisam descer do avião imediatamente. O(a) tripulante Fernando desceu do avião. Chegou na cidade. O(a) tripulante Camila desceu do avião. Chegou na cidade. O(a) piloto Gabriel desceu do avião. Chegou na cidade. Quando comecei a escreve esse post, minha idéia era usar parâmetros tipados nos métodos embarcar e desembarcar da classe A747, no entanto, eu ainda não sabia porque, mas o PHP permite parâmetros tipados apenas de tipos que o programador define, isso é, um Avião, uma Pessoa, etc. Já parâmetros tipados do tipo String, Array, eu não consegui. Então eu omiti o uso de parâmetros e criei uma variável $tripulantes na classe A747, e usei ela dentro desses métodos. Acredito que ficou até melhor, porque usei a agregação, o que encaixa perfeitamente nesse contexto, ou seja, um tripulante está agregado a um avião, mas se o avião cair, um tripulante ainda pode se salvar. :D Mas apenas para demonstrar os parâmetros tipados, criei um método setTripulante, e fui incrementando a variável $tripulantes da classe A747. Perceba que nesse método sempre será do tipo Passageiro, pois se não for, o interpretador já acusa um erro antes de executar o método. Com isso, não precisamos usar o instanceof para verificar se tal objeto é uma instância de uma classe. OBS: Usei echo nos métodos para ficar um pouco funcional, pois se usasse return, não daria certo. Testem aí, ele imprime alguns valores. Acredito que o único ruim, seria essa associação "É UM" entre passageiro, tripulante e piloto. Além disso, eu interpretei tripulante como uma pessoa. akoskaseo :D E aí, o que acharam? :D Compartilhar este post Link para o post Compartilhar em outros sites
Gabriel Heming 766 Denunciar post Postado Maio 15, 2012 [...]parâmetros tipados do tipo String, Array, eu não consegui[...] PHP não implementa mesmo. Já em vários exemplos o uso destes, entretanto, nunca funcionou. Massa o seu exemplo. Só mudaria de setTripulante para addTripulante, por questões de coesão. Compartilhar este post Link para o post Compartilhar em outros sites
Bruno Augusto 417 Denunciar post Postado Maio 15, 2012 Na verdade, ao que parece segundo a pouca documentação, ela implementa sim, mesmo que em caráter experimental, através das classes concretas de SplType. Compartilhar este post Link para o post Compartilhar em outros sites
Gabriel Heming 766 Denunciar post Postado Maio 15, 2012 Procurando sobre SplType: Warning: This function is currently not documented; only its argument list is available. E depois o PHP quer evoluir '-'. Não vou conseguir testar agora no momento. Mas se isso é verdade, é um, pelo menos algum, avanço no type hint. Edit--------- Pelo que eu entendi, ele apenas lança exceptions (o que já é um grande avanço) No java seria assim: Class MinhaClasse { private int numero; public void setNumero( int numero ) { this.numero = numero; } } No php, utilizando SplType. Class MinhaClasse { private $numero; public function setNumero( $numero ) { $this->numero = new SplInt( $numero ); } } Em ambos os casos, se algum "malaco" colocar algo que não seja INT, uma exceptions vai ser lançada (Java -> NumberFormatException, PHP -> UnexpectedValueException ) Já vai ajudar bastante no type hint. Compartilhar este post Link para o post Compartilhar em outros sites
Bruno Augusto 417 Denunciar post Postado Maio 15, 2012 Criar nossas próprias classes de type hint ainda parece ser uma alternativa mais viável. ?P Compartilhar este post Link para o post Compartilhar em outros sites
Gabriel Heming 766 Denunciar post Postado Maio 15, 2012 Se não houver outra escolha, própria da linguagem de programação, seria mais viável. Entretanto existe. Experimental, mas existe. Compartilhar este post Link para o post Compartilhar em outros sites
FK. 0 Denunciar post Postado Maio 15, 2012 Massa o seu exemplo. Só mudaria de setTripulante para addTripulante, por questões de coesão. Vlw. Observando o que você disse, só agora percebi que como estou adicionando tripulantes, faz mais sentido add do que set. Eu também faria essa modificação. :D Mas sei la, acho que tem algo incorreto nesse meu exemplo... :/ Compartilhar este post Link para o post Compartilhar em outros sites
FK. 0 Denunciar post Postado Maio 16, 2012 Galera, apenas para termos um pouco mais de conteúdo no tópico, esse artigo (em Java) dexa um pouco mais claro o que o Henrique quis dizer quando uma interface tem que ter seus métodos públicos porque define a relação com o mundo exterior. Com a definição do Henrique e desse artigo, ficou extremamente claro sobre o assunto, tanto é que, agora realmente entendi os conceitos. Vlw! hehe :) Edit -- Uma pergunta, se eu quero aproveitar de todos os recursos da POO, então todo método que deveria ser público, isso é, o que define a interface com o mundo exterior, e definisse o que o objeto faz, deveria estar numa interface? Pode existir métodos públicos que não deveriam estar numa interface? Métodos privados, sendo privados, devem sempre estar numa classe, pois eles são o funcionamento interno de uma classe, certo?(Nós nem podemos declarar métodos privados em interfaces...) Compartilhar este post Link para o post Compartilhar em outros sites
Henrique Barcelos 290 Denunciar post Postado Maio 16, 2012 Uma pergunta, se eu quero aproveitar de todos os recursos da POO, então todo método que deveria ser público, isso é, o que define a interface com o mundo exterior, e definisse o que o objeto faz, deveria estar numa interface? Não... muita hora nessa calma... (ou quase isso)... Uma interface é importante para especificar as operações esperadas em um CONJUNTO de objetos. Se o objeto é único na aplicação, não possui nem similares, então não tem porque definir uma interface. Métodos privados, sendo privados, devem sempre estar numa classe, pois eles são o funcionamento interno de uma classe, certo?(Nós nem podemos declarar métodos privados em interfaces...) Exatamente. Não existem métodos protected nem private em interfaces pois eles são internos, não se comunicam com o mundo exterior. Compartilhar este post Link para o post Compartilhar em outros sites