Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
Olá colegas
Estou tendo o seguinte problema, ao clonar um objeto que contém um atributo que é um array aparentemente o PHP está mantendo a mesma referência de memória tanto para a instância do objeto original quanto para sua cópia. Segue código de exemplo:
<?php
public $nome;
}
public $atributo = "";
private $pessoas = array();
# Adiciona no Array
public function adicionar(Pessoa $pessoa) {
array_push($this->pessoas, $pessoa);
}
# Retorna indice do array
public function pegar($indice)
{
return $this->pessoas[$indice];
}
}
$pessoas = new Pessoas();
$pessoas->atributo = "Original";
$pessoas2 = new Pessoas();
$pessoas2 = clone $pessoas;
$pessoas2->atributo = "Cópia";
$pessoas2->pegar(0)->nome = "Nome 2";
echo var_dump($pessoas);
echo "<br><br>";
echo var_dump($pessoas2);
?>
O Resultado é esse
>
object(Pessoas)#2 (2) { ["atributo"]=> string(8) "Original" ["pessoas:private"]=> array(1) { [0]=> object(Pessoa)#1 (1) { ["nome"]=> string(6) "Nome 2" } } }
object(Pessoas)#4 (2) { ["atributo"]=> string(5) "Cópia" ["pessoas:private"]=> array(1) { [0]=> object(Pessoa)#1 (1) { ["nome"]=> string(6) "Nome 2" } } }
Ou seja, quando seto o nome para o clone ele afeta também o objeto original... Não sei o que estou fazendo de errado...
Estou usando o PHP 5.2.6
Obrigada pela resposta Rick, entretanto para mim continuou o problema... coloquei o método __clone() e o resultado foi o mesmo...
Com relação a criação da instância no código, coloquei somente para deixar claro que o retorno que eu queria era do tipo Pessoas, apesar de o PHP nesse caso igonorar a declaração por causa da atribuição na linha posterior...
Com relação a ser por referência, (não conheço muito de PHP) mas em java ou c# quando clono um objeto ele clona todo o estado da classe, fazendo uma cópia fiel da instância para outro endereço de memória, o que no php fez parcialmente pois o atributo $atributo foi clonado perfeitamente entretanto somente o array não foi.
Segue código alterado
<?php
public $nome;
}
public $atributo = "";
private $pessoas = array();
# Adiciona no Array
public function adicionar(Pessoa $pessoa) {
array_push($this->pessoas, $pessoa);
}
# Retorna indice do array
public function pegar($indice)
{
return $this->pessoas[$indice];
}
public function __clone(){
$novo = new Pessoas();
foreach($this->pessoas as $each){
$novo->pessoas[] = clone $each;
}
return $novo;
}
}
$pessoas = new Pessoas();
$pessoas->atributo = "Original";
$pessoas2 = new Pessoas();
$pessoas2 = clone $pessoas;
$pessoas2->atributo = "Cópia";
$pessoas2->pegar(0)->nome = "Nome 2";
echo var_dump($pessoas);
echo "<br><br>";
echo var_dump($pessoas2);
?>
ObrigadaKatya,
O comportamento do PHP é exatamente o esperado, você clonou a lista, não o objeto pessoa.
Veja as duas situações:
<?php
class Person {
private $name;
public function __construct( $name ){
$this->setName( $name );
}
public function setName( $name ){
$this->name = $name;
}
}
<?phpprivate $personArray;
public function __construct(){
$this->personArray = array();
}
public function add( Person $person ){
$this->personArray[] = $person;
}
/**
* @return Person
*/
public function get( $offset ){
if ( isset( $this->personArray[ $offset ] ) ){
return $this->personArray[ $offset ];
} else {
throw new OutOfRangeException( "Não existe uma pessoa para o índice especificado" );
}
}
}
<?php
$people = new People();
$person1 = new Person( 'João Batista Neto' );
$people->add( $person1 );
$person2 = clone $person1;
$person2->setName( 'Katya_crisd' );
$people->add( $person2 );
var_dump( $people->get( 0 ) , $people->get( 1 ) );
A saída:
object(Person)#10 (1) {
["name":"Person":private]=>
string(10) "João Neto"
}
object(Person)#11 (1) {
["name":"Person":private]=>
string(11) "Katya_crisd"
}
Como o clone foi feito para o objeto pessoa, a modificação no segundo objeto não reflete no primeiro.
Agora, veja só:
<?php
$person1 = new Person( 'João Batista Neto' );
$person2 = new Person( 'Katya_crisd' );
$people1 = new People();
$people1->add( $person1 );
$people1->add( $person2 );
$people2 = clone $people1;
$people2->get( 0 )->setName( 'Teste' ); //Apenas a lista foi clonada, não os objetos Person
var_dump( $people1->get( 0 ) , $people1->get( 1 ) );
A saída:
object(Person)#9 (1) {
["name":"Person":private]=>
string(5) "Teste"
}
object(Person)#10 (1) {
["name":"Person":private]=>
string(11) "Katya_crisd"
}
Como pode ver, apenas a lista foi clonada, não seus objetos Person.
Para resolver isso, você precisa clonar os objetos da lista também, veja só:
<?php
class People {
private $personArray;
public function __construct(){
$this->personArray = array();
}
public function __clone(){
$oldArray = $this->personArray;
$newArray = array();
foreach ( $oldArray as $person ){
$newArray[] = clone $person;
}
$this->personArray = $newArray;
}
public function add( Person $person ){
$this->personArray[] = $person;
}
/**
* @return Person
*/
public function get( $offset ){
if ( isset( $this->personArray[ $offset ] ) ){
return $this->personArray[ $offset ];
} else {
throw new OutOfRangeException( "Não existe uma pessoa para o índice especificado" );
}
}
}
Agora, veja só:
<?php
$person1 = new Person( 'João Batista Neto' );
$person2 = new Person( 'Katya_crisd' );
$people1 = new People();
$people1->add( $person1 );
$people1->add( $person2 );
$people2 = clone $people1;
$people2->get( 0 )->setName( 'Teste' );
var_dump( $people1->get( 0 ) , $people1->get( 1 ) );
A saída:
object(Person)#9 (1) {
["name":"Person":private]=>
string(18) "João Batista Neto"
}
object(Person)#10 (1) {
["name":"Person":private]=>
string(11) "Katya_crisd"
}
Se observarmos o objeto $people2, a saída será:
object(People)#12 (1) {
["personArray":"People":private]=>
array(2) {
[0]=>
object(Person)#13 (1) {
["name":"Person":private]=>
string(5) "Teste"
}
[1]=>
object(Person)#14 (1) {
["name":"Person":private]=>
string(11) "Katya_crisd"
}
}
}
Ou seja, se existe uma composição ou agregação, a clonagem do objeto deve ser feita para toda ela, caso contrário, toda modificação feita às instâncias da composição clonada refletirá nas instâncias dos objetos da composição original.
;)
Primeiramente:
$pessoas2 = new Pessoas();
$pessoas2 = clone $pessoas;Se você vai criar um clone, pq cria uma instancia antes?
Adicione o seguinte método à classe Pessoas:
}Chama-se Cópia Profunda do objeto.Atribuições de objeto no PHP 5 são feitas por referência...Anh? O que é isso?
Na prática, quando você faz:
$obj1 = new Objeto();
$obj2 = $obj1;Ambas as variáveis apontam para um mesmo objeto...Se você alterar $obj2, irá refletir também em $obj1
Sempre haverá esse problema quando houver composição, como no seu caso, pois a classe Pessoas CONTÉM Pessoa
Pesquise um pouco mais a respeito.