Php通过值传递对象

Php通过值传递对象,php,recursion,reference,Php,Recursion,Reference,我正在用php玩一点递归。不幸的是,php重视智能复制思想,默认情况下通过引用传递对象并没有使它变得更容易。出现问题的原因是迭代编号X所做的修改在迭代ex-2中可见 例如: /** * Silly function to find last element in array * @param ArrayObject $input */ function process(ArrayObject $input) { if ($input->count() == 1) {

我正在用php玩一点递归。不幸的是,php重视智能复制思想,默认情况下通过引用传递对象并没有使它变得更容易。出现问题的原因是迭代编号X所做的修改在迭代ex-2中可见

例如:

/**
 * Silly function to find last element in array
 * @param ArrayObject $input  
 */
function process(ArrayObject $input) {
    if ($input->count() == 1) {
        return $input->getIterator()->current();
    }
    $ar = $input->getArrayCopy();
    array_shift($ar);
    $input->exchangeArray($ar);
    return process($input);
}

$in = new ArrayObject(range('a', 'd'));
echo 'Before ' . PHP_EOL;
var_dump($in);
echo PHP_EOL . 'Process - last element is: ' . process($in) . PHP_EOL;
echo 'After ' . PHP_EOL;
var_dump($in);
输出为

Before 
object(ArrayObject)#1 (1) {
  ["storage":"ArrayObject":private]=>
  array(4) {
    [0]=>
    string(1) "a"
    [1]=>
    string(1) "b"
    [2]=>
    string(1) "c"
    [3]=>
    string(1) "d"
  }
}

Process - last element is: d
After 
object(ArrayObject)#1 (1) {
  ["storage":"ArrayObject":private]=>
  array(1) {
    [0]=>
    string(1) "d"
  }
}
正如您看到的递归也修改了原始的$in变量一样,我所期望的是,每个新的迭代都将对值的副本进行操作。在这个例子中,它是不需要的,但在递归函数更复杂的情况下会发生什么呢

简单解决方案-克隆

function process(ArrayObject $input) {
    $input = clone ($input);
    if ($input->count() == 1) {
        return $input->getIterator()->current();
    }
    $ar = $input->getArrayCopy();
    array_shift($ar);
    $input->exchangeArray($ar);
    return process($input);
}
好的,可以,但若输入是非常复杂的多对象嵌套递归结构呢? 好的,然后我可以序列化并取消序列化值,作为深度复制的替代

function process(ArrayObject $input) {
    $input = unserialize(serialize($input));
    if ($input->count() == 1) {
        return $input->getIterator()->current();
    }
    $ar = $input->getArrayCopy();
    array_shift($ar);
    $input->exchangeArray($ar);
    return process($input);
}
完美-它可以工作,但在每次迭代中取消/序列化(尤其是在有大量$input的情况下)会浪费一些时间和cpu

有没有其他方法可以做到这一点,让我不必担心我需要“修改一下”以使用php作为标准用法

//编辑带有Tigrang建议的示例

你的建议很有趣,但是

function process(ArrayObject $input) {
    $input = new ArrayObject(($input));
    $input->offsetSet(null, 'f');
}

$in = new ArrayObject(range('a', 'd'));
echo 'Before ' . PHP_EOL;
var_dump($in);
process($in);
echo 'After ' . PHP_EOL;
var_dump($in);

 After 
object(ArrayObject)#1 (1) {
  ["storage":"ArrayObject":private]=>
  array(5) {
    [0]=>
    string(1) "a"
    [1]=>
    string(1) "b"
    [2]=>
    string(1) "c"
    [3]=>
    string(1) "d"
    [4]=>
    string(1) "f"
  }
}
它仍然保持对外部变量的引用

//编辑2

class Engine {

    public $power = 999;

}

class Car {

    public $name = '';
    public $engine = '';

    public function __construct($name, $power) {
        $this->name = $name;
        $this->engine = new Engine();
        $this->engine->power = $power;
    }

}

function process(ArrayObject $input) {
    $input = new ArrayObject(($input->getArrayCopy()));
    $ford = $input[0];
    $ford->name = 'Audi';
    $ford->engine->power  = 1500;
}

$ar = array(new Car('Ford',  130));
$in = new ArrayObject($ar);
echo 'Before ' . PHP_EOL;
var_dump($in);
process($in);
echo 'After ' . PHP_EOL;
var_dump($in);

好了,这是PHP的一个限制。正如您所指出的,这是因为PHP5x中有两个东西不是互补的

  • 对象始终作为引用传递
  • clone()只进行浅层复制,语言中没有固有的深层复制机制

unserialize(serialize($obj)
是目前唯一可用的(效率极低的)解决方法。让我们希望诸神在即将发布的版本中解决其中一些问题,而不是仅仅在大肆宣传(和延迟)的版本6中打破他们关于如何实现unicode的想法!

$input=new ArrayObject($input);


据我所知,复制深度嵌套且比序列化更快:

您考虑过使用数组而不是对象吗?使用
克隆如何?@Truth-是的,但我想使用objects@zerkms-请阅读第三个灰色框下的说明,副本不是完美的解决方案(不幸的是)@mrok:为什么?迭代对象而不是数组没有任何好处。事实上,相反,数组有更好的性能,使用数组函数更容易遍历和操作。有趣的是,但仍然不能解决问题,请查看问题更新。然后尝试
$input=new ArrayObject($input->getArrayCopy());
仍然比序列化快一点-但是仍然不能处理对象,请检查第二次更新。我现在看到了问题所在。我想序列化是唯一的选择。