Solucionado (ver solução)
Solucionado
(ver solução)
6
respostas

Métodos mágicos

Fala pessoal, ao invés de criar getters e setters como no curso eu usei os métodos mágicos na classe pai, que no caso é a produto. Como eu faço na classe filha livro? Ele não herdou e quando criei os mágicos de novo parou de aparecer as infos de produto, só funcionou usando

public function getIsbn(){
return $this->isbn;
}
6 respostas

Oi Franklin, tudo bom?

Compartilha com a gente aqui seu código? Tanto da classe Produto quanto da classe Livro

Assim fica mais fácil entender o cenário e te dar um direcionamento =)

Abraço!

A ideia era herdar os getters e setters da classe pai, mas aparentemente não funciona assim.

class Produto
{

    private $id;

    private $nome;

    private $preco;

    private $descricao;

    private $categoria;

    private $usado;

    public function __construct($nome, $preco, $descricao, Categoria $categoria, $usado)
    {
        $this->nome = $nome;
        $this->preco = $preco;
        $this->descricao = $descricao;
        $this->categoria = $categoria;
        $this->usado = $usado;
    }

    public function __set($nome, $valor)
    {
        $this->$nome = $valor;
    }

    public function __get($nome)
    {
        return $this->$nome;
    }

    public function precoComDesconto($valorDesconto = 0.1)
    {
        if ($valorDesconto > 0 && $valorDesconto <= 0.5)
            $this->preco -= $this->preco * $valorDesconto;
        return $this->preco;
    }

    public function temIsbn()
    {
        return $this instanceof Livro;
    }

    public function calculaImposto()
    {
        return $this->preco * 0.195;
    }
}
 class Livro extends Produto
{

    private $isbn;

    public function calculaImposto()
    {
        return $this->preco * 0.065;
    }
}

Oi Franklin,

esses dois métodos:

 public function __set($nome, $valor)
    {
        $this->$nome = $valor;
    }

    public function __get($nome)
    {
        return $this->$nome;
    }

Não são métodos mágicos, pois não fazem parte da API da linguagem. Inclusive, criar um getter e um setter só pra todos os atributos usando reflexão interpretada não é visto como uma boa prática.

Isso porque, caso esse código cresça e surjam regras de negocio especificas na definição ou busca do valor de um atributo a gente precisaria fazer verificações no getter/setter para descobrir qual atributo está sendo passado por parâmetro. Algo como:

public function __set($nome, $valor)
    {
    if($nome == "preco" && $valor > 0)    
            $this->$nome = $valor;
    else if($nome == "preco")
        throw new Exception("o preço do produto não pode ser negativo");
    // a mesma ideia se repete pra qualquer outro atributo
    }

Quanto a herança desse método. Teoricamente, não há problema algum utilizar os métodos explicitamente dentro da classe filha:

 class Livro extends Produto
{

    private $isbn;

    public function calculaImposto()
    {
        return $this->__get("preco") * 0.065;
    }
}

O problema aqui é que estamos tentando acessar a propriedade privada preço, fora da classe na qual ela foi declarada:

class Livro extends Produto
{

    private $isbn;

    public function calculaImposto()
    {
       return $this->preco * 0.065;
    }
}

Nesse caso, para que o atributo seja visivel na classe filha, ele precisa estar declarado como protegido:

class Produto
{

    private $id;

    private $nome;
    // agora esse atributo é visivel nas classes filhas tb =)    
    protected $preco;

    private $descricao;

    private $categoria;

    private $usado;
...

Abraço!

Eu tinha a dúvida quanto ao usar ou não e justamente pelo que disse suspeitava não ser uma boa prática. Entretanto quanto a não serem métodos mágicos e não fazerem parte da api ficou confuso pra mim tendo em vista que peguei na documentação do PHP

http://php.net/manual/pt_BR/language.oop5.magic.php

solução!

Opa, realmente, comi bola nessa haha

Parece que a ideia dos métodos __get e __set é serem chamados pela própria linguagem mesmo. Portanto, fazem parte da API sim.

O código não funcionava pela questão de visibilidade private do atributo. Alterar para protected resolveria o problema nos dois casos =)

Já estava pensando que eu tinha ficado louco huauhau. E quanto a questão do protected eu já tinha visto, mas como normalmente é melhor deixar como privado e os métodos são mágicos e herdados pelas filhas achei que tivesse uma "mágica" por trás que fizesse funcionar. Vlw