2013-02-08 59 views
3

我正在研究一个从PHP 4迁移到PHP 5.2的非常老的项目,现在我们正在将项目迁移到PHP 5.4。我们想出了一些参考错误。这里有一些示例代码正在扰乱我。为什么在普通对象实例化和通过引用实例化对象之间存在差异?

<?php 

class book_shelf 
{ 
    protected $_elements = array(); 

    function addBook(&$element){ 
     $this->_elements[] =& $element; 
    } 

    function printBooks(){ 
     print(json_encode($this->_elements)); 
    } 
} 

class book 
{ 
    function __construct($title, $author="unknown") { 
     $this->title = $title; 
     $this->author = $author; 
    } 

    public $title = NULL; 
    public $author = NULL; 
} 

function createBookShelf(){ 
    $bookshelf1 = new book_shelf(); 

    for ($i = 0; $i < 3; $i++){ 
     $book1 = new book("Book $i"); 
     $bookshelf1->addBook($book1); 
    } 

    $bookshelf1->printBooks(); 
} 

createBookShelf(); 

?> 

我希望这可以创建3本独立的书。但是元素数组中的每个对象最终都指向最后一个变量。另一方面,如果我通过引用创建一本新书,那么一切正常。 (例如$book1 =& new book("Book $i");)下面是示例代码:

<?php 

class book_shelf 
{ 
    protected $_elements = array(); 

    function addBook(&$element) { 
     $this->_elements[] =& $element; 
    } 

    function printBooks(){ 
     print(json_encode($this->_elements)); 
    } 
} 

class book 
{ 
    function __construct($title, $author="unknown") { 
     $this->title = $title; 
     $this->author = $author; 
    } 

    public $title = NULL; 
    public $author = NULL; 
} 

function createBookShelf() { 
    $bookshelf1 = new book_shelf(); 

    for ($i = 0; $i < 3; $i++){ 
     $book1 =& new book("Book $i"); 
     $bookshelf1->addBook($book1); 
    } 

    $bookshelf1->printBooks(); 
} 

createBookShelf(); 

我的印象是,通过在PHP 5.4参考创建对象是没有必要的。任何想法为什么我得到不同的结果?

+3

删除*所有*对对象的引用。对象在默认情况下通过引用进行处理(分配,传递给函数/方法,返回)。 – 2013-02-08 23:34:32

+0

'$ this - > _ elements [] =&$ element;'你期望做什么? – 2013-02-08 23:35:09

+0

从这一行删除&$ this - > _ elements [] =&$ element;'修正了问题 – 2013-02-08 23:45:15

回答

2

这是一个逻辑错误,而不是PHP版本相关。让我们看看下面的代码片段:

//echo "phpinfo: " . phpinfo(); 
for ($i = 0; $i < 3; $i++){ 
    $book1 = new book("Book $i"); 
    $bookshelf1->addBook($book1); 
} 

... 

function addBook(&$element){ 
    $this->_elements[] =& $element; 
} 

发生了什么事?您通过参考传递$ book。但是在每一个循环中你都会改变参考值。在for循环结束时,$ book指向最后创建的书对象,因此引用。 (过这样的错误,一旦太;)

结论:你addBook函数看起来像这样:

function addBook($element){ 
    $this->_elements[] = $element; 
} 

,并保持,增加了本书不变的代码 - 这意味着像在上面的例子中没有&


* 关于= &新... *

首先,如果你这样做,你会得到如下的警告,PHP 5.3:

弃用:分配不推荐使用新参考的返回值

因此,您不应将其用于新代码。

+0

你能解释为什么$ book1 =&新书(“Book $ i”);功能不同?该文档似乎表明“... =&new ...”现在的功能与“... = new ...”相同,但显然并非如此。我的假设是,即使PHP现在在实例化过程中分配时默认使用了引用,那么以前的引用“破坏”=&提供(如http://stackoverflow.com/a/3200017/459966中所述)仍然是现行。 – Aaronius 2013-02-08 23:57:10

+0

@Aaronius会尝试...... – hek2mgl 2013-02-08 23:59:54

+0

虽然我确信布拉德对目前为止所有人的评论都很感激,但我不认为有人真的回答了他的问题,即:“任何想法为什么我会得到不同的结果?看起来他已经知道如何解决这个问题,但是想知道为什么他的两个例子有不同的表现。 – Aaronius 2013-02-09 00:27:11

1

正如你写的这是PHP 4代码最初。这两种结构:

$book1 =& new book("Book $i"); 

function addBook(&$element){ 
    $this->_elements[] =& $element; 
} 

不需要任何更长的时间。第一个是这从来都不是正确的事,但要得到的东西在PHP 4个工作使用对象,而不是克隆对象的所有时间

二是“按引用传递”,“通过引用新的”,这可以是一个有效的概念,但是对于PHP 5 中的对象而言,这不是必需的,对于作为对象的参数,不应该使用

PHP 5中的内存管理已经有了很大改进,然后在PHP 5.3中又一次得到了改进。 PHP 5.4通过提供警告帮助您迁移代码。特别是“新的参考”可以很容易地发现和修复。

老(PHP 4):

$book1 =& new book("Book $i"); 

新(当前的PHP版本):

$book1 = new book("Book $i"); 

(不,它不会再回来:))。对于您通过引用传递,我建议,当你重构代码,删除引用和也的类型提示的对象类型的方法:

老(PHP 4):

function addBook(&$element){ 
    $this->_elements[] =& $element; 
} 

新(当前的PHP版本):

function addBook(Book $element){ 
    $this->_elements[] = $element; 
} 

那么你不仅解决一个古老的问题,而且还要确保此功能只与预期的类型调用,你可以看到它总是意味着需要一个对象(而不是一个变量引用因为PHP 4是有限的,所以它仅在PHP 4中用于对象。这不再需要,可以(也应该扔掉这个旧的垃圾!)被删除)。

将您的代码库置于版本控制之下,以便您可以轻松地将更改应用于您的代码库,而不用担心破坏以前的任何工作。


我希望它可以创建3本不同的书籍。但是元素数组中的每个对象最终都指向最后一个变量。

这里的实际问题是您使用传递引用。当你分配

$book1 = new book("Book $i"); 

$book1的refcount是一个,它并没有标记为参考。现在把它当作参考到$bookshelf1->addBook($book1)方法把它变成为2的引用计数的引用,因为该方法的参考再次分配给类的私有成员内部:

for ($i = 0; $i < 3; $i++) 
{ 
    $book1 = new book("Book $i"); 
    $bookshelf1->addBook($book1); 
} 

... 

function addBook(&$element){ 
    $this->_elements[] =& $element; 
} 

然后,您可以更改现在创建参考。

所以,现在当你用实例更改代码:

$book1 = & new book("Book $i"); 

你总是 - 每一次循环 - 创建一个新的别名(参考)只能用相同的变量名。因为您将此作为参考传递,因此您将其作为参考分配的新别名。因此,Book中的数组指向三个不同的引用 - 不是相同引用的三倍。

我希望这能更好地解释这个问题。这也是我们之所以这样说的原因:除非你知道你在做什么,否则不要使用引用。 PHP 4的情况是,许多用户过去常常使用引用而没有完全理解它是如何工作的(这是可以理解的,因为它在PHP中不容易理解,我还需要将我的头围绕一下,直到我找到一个很好的描述来分享 - 希望它可以这次:))。在这里明确使用PHP 5的好处是,您不需要再使用引用来更容易地编写和读取代码。


相关: