Php 按值传递对象

标签 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(特别是在输入巨大的$输入时)。

有没有其他方法可以做到这一点,让我不用担心我需要“稍微修改”才能使用 php 进行标准用法。

//使用 Tigrang 建议编辑示例

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 的一个限制。正如您所指出的,发生这种情况是因为 PHP 5x 中的两件事是不互补的。

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

unserialize(serialize($obj) 是当前唯一可用的(非常低效的)解决方法。让我们希望上帝在即将到来的版本中解决其中一些问题,而不是只是对如何在大肆宣传(和延迟)的版本 6 中实现 unicode 感到头疼!

关于Php 按值传递对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12082208/

相关文章:

php - 我可以修改 'wc-template-functions.php' 文件中的 WooCommerce 函数,还是应该坚持使用 'functions.php' 文件进行此类修改?

更改指针的值而不在函数中调用它?

boost - ptr_map 和指针

php - 我怎样才能拥有一系列电子邮件并确保它们都已发送?

php - 周期性日历事件

javascript - 解析 Freebase 主题 HTTP API - JSON 和 Javascript

c++ - 自调用递归 lambda 的 std::bad_function_call 但没有提示

python - Python中的递归循环函数

reference - 在哪里可以找到 CG 着色器语言的引用?

php - 如何使用 php jquery 制作高效的通知生成器