Php按值传递对象

时间:2012-08-22 22:18:36

标签: php recursion reference

我在php中使用递归播放了一下。不幸的是,php值智能复制的想法和默认情况下通过引用传递对象并不容易。出现问题是因为迭代编号X的修改在迭代ex X-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);
}

完美 - 它可以工作,但是在每次迭代中取消/序列化都会浪费时间和cpu(特别是使用巨大的$ input)。

有没有其他方法可以做到这一点,让我不必担心我需要'破解'使用php进行标准使用。

// TIGNng建议的编辑示例

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);

2 个答案:

答案 0 :(得分:3)

AFAIK,这是PHP的限制。正如你所指出的那样,这是因为PHP 5x中的两件事并不是免费的。

  • 对象始终作为参考传递
  • clone()只执行浅拷贝,并且语言中没有固有的深层复制机制

unserialize(serialize($obj)是目前唯一可用的(非常低效)解决方案。让我们希望众神能够在即将到来的版本中解决其中的一些问题,而不是仅仅打破如何在大肆宣传(延迟)的版本6中实现unicode!

答案 1 :(得分:0)

为什么不$input = new ArrayObject($input);

据我所知,它是深层嵌套的复制品,比序列化更快:http://viper-7.com/kHLCCP