13
respostas

iterar objeto composto

Boa noite, estou com uma dúvida, sobre como definir uma propriedade de um objeto composto, vou tentar reproduzir um exemplo:

Pessoa.php

<?php
class Pessoa extends \IteratorIterator{
private NomeCompleto $nomeCompleto

public function __construct(NomeCompleto $nomeCompleto){
$this->nomeCompleto = $nomeComopleto;
}
public function __get($atributo){
return $this->$atributo ;
}
public function __set($atributo, $valor){
$this->$atributo = $valor;
}
public function getIterator()
    {
        return new \ArrayIterator($this->sobrenome);
    }
}

NomeCompleto.php

<?php
class NomeCompleto{
private string $nome;
private ?string $sobrenome;

public function __construct($nome, $sobrenome){
$this->nome = $nome;
$this->sobrenome = $sobrenome;
}
public function __get($atributo){
return $this->$atributo ;
}
public function __set($atributo, $valor){
$this->$atributo = $valor;
}
}

Sem se preocupar com a funcionalidade do exemplo, digamos que a classe Pessoa possua não só uma propriedade ($nomeCompleto) e sim uma série, que devem ser uma instancia de NomeCompleto. E que eu queira alterar o $sobrenome de todos os atributos, eu tentei da seguinte forma: teste.php

<?php

$pessoa = new Pessoa(new NomeCompleto("João", NULL));

foreach($pessoa as $valor){
    $valor->sobrenome = "Silva";
}

e não deu certo, o que está errado?

13 respostas

Marcos, sendo muito sincero, eu não consegui entender sua dúvida...

rsrs

Seu código não fez muito sentido, então não entendi qual o propósito dele. Talvez até tenha sido pela falta de indentação que dificultou minha leitura, não sei. Consegue tentar exemplificar de outra forma?

na verdade não consegui pensar em um exemplo prático mas vou tentar melhorar:

Carro.php

<?php
class Pessoa extends \IteratorIterator{
    private Peca $motor;
    private Peca $pneus;
    private Peca $amortecedor;

    public function __construct(
        Peca $motor,
        Peca $pneus,
        Peca $amortecedor
    ){
        $this->motor = $motor;
        $this->pneus = $pneus;
        $this->amortecedor = $amortecedor;
    }
    public function __get($atributo){
        return $this->$atributo ;
    }
    public function __set($atributo, $valor){
        $this->$atributo = $valor;
    }
    public function getIterator(){
            return new \ArrayIterator($this);
    }
}

Peca.php

<?php

class Peca{

    private string $marca;
    private string $modelo;
    private float $preco;

    public function __construct(
        ?string $marca,
        string $modelo,
        float $preco
    ){
        $this->marca = $marca;
        $this->modelo = $modelo;
        $this->preco = $preco;
    }

    public function __get($atributo){
        return $this->$atributo ;
    }
    public function __set($atributo, $valor){
        $this->$atributo = $valor;
    }

}

teste.php

<?php

$carro = new Carro(
    new Peca(NULL, "1.8", 15000.00),
    new Peca("Pirelli", "P7", 500.00),
    new Peca("Cofap", "ar", 1000.00)
);

foreach($carro as $peca){
    $peca->marca = "VW";
}

no exemplo acima estou tentando alterar a marca de todas a peças, porém no PHP isso aparentemente não é possível mesmo usando Itarator,

Então, Marcos. Esse exemplo não funciona porque possui diversos erros tanto de sintaxe quanto de lógica, mas o que você está tentando fazer é possível sim.

Dá uma olhada: https://3v4l.org/4HmUZ

então o único erro estava em GetIterator?:

public function getIterator()
    {
        return new \ArrayIterator([
            $this->motor,
            $this->pneus,
            $this->amortecedor,
        ]);
  1. Você estava estendendo a classe errada
  2. Você, mesmo estendendo uma classe, não chamava seu construtor base
  3. Você definiu a classe como Pessoa e instanciou como Carro
  4. Estava criando um iterator de Array a partir de um objeto
  5. A marca é uma string e você estava inicializando como NULL em um dos casos

Agora um ponto muito importante: Esse código funciona, mas ainda assim não faz muito sentido. Não consigo pensar em uma situação real onde isso seria aplicado.

Além disso, tem que tomar cuidado pois não há garantia de que todos os itens a serem iterados terão a propriedade marca e você pode acabar definindo-a de forma dinâmica.

esses erros de digitação foi agora que estava tentando melhorar um exemplo daí esqueci de mudar de primeiro exemplo (Pessoa) para o segundo (Carro) quanto a "marca" estava assim ?string $marca no construtor mas esqueci de fazer o mesmo na propriedade. Digitei esse código aqui mesmo nem fui conferir no VSCode se tava certo e como o fórum da alura ainda não é uma IDE não pegou hahaha.

Pra mim no código que estou tentando desenvolver fez sentido, é uma classe com 11 atributos em que todos eles possuem as mesmas 3 características.

Pensei em fazer como no curso e criar uma classe abstrata e emplementar em 11 classes, mas achei que seria mais complicado e acabaria aumentando demais as linhas de código.

com o mesmo exemplo do carro:

classe Motor:

Motor implements Peca

classe Carro:

Carro
    private Motor $motor;

faz mais sentido ?

Marcos, extraia esses 3 atributos pra uma outra classe, de forma semelhante ao padrão Flyweight. Dessa forma você não vai ter essa repetição de código.

ainda não fiz o curso que aborda Flyweight, mas não foi isso que fiz (mesmo sem saber) quando extraí as características das peças do carro para a class peça? ficando assim:

private Peca $motor;

Quando você extrai o que seria repetido em todos os outros objetos, você não precisa mais desse loop. Basta passar esse objeto no construtor dos demais que você estiver criando, entende?

não ficou claro pra mim, você pode me explicar mais?

Você consegue me dar o exemplo real que você está pensando em aplicar? Aí eu posso ver se realmente faz sentido a sugestão... :-)

esse foi o exemplo mais próximo do real que consegui.

Então, Marcos...

Esse exemplo, semanticamente falando, não faz muito sentido.

Se todos as peças têm a mesma marca, você vai compartilhar o objeto. Se as peças possuem marcas diferentes, os objetos são diferentes e suas alterações também devem ser individuais.

:-)