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 では参照によるオブジェクトの作成は必要ないという印象を受けました。なぜ私は異なる結果を得ているのですか?

4

2 に答える 2

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 は最後に作成された book オブジェクトを指し、その参照を指します。(このエラーも一度ありました;)

結論: addBook 関数は次のようになります。

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

本を追加するコードはそのままにしておきます。つまり、上記の例で&.


* =&新規について... *

まず、これを行うと、php 5.3 の時点で次の警告が表示されます。

非推奨: 参照による new の戻り値の割り当ては非推奨です

したがって、新しいコードには使用しないでください。

于 2013-02-08T23:42:55.550 に答える
1

あなたが書いているように、これはもともとPHP 4コードです。これらの 2 つの構造:

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

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

はもう必要ありません。最初のものは「参照による新規」です。これは決して正しいことではありませんでしたが、PHP 4でオブジェクトを使用して何かを動作させるために必要であり、常にオブジェクトを複製するのではありません

2 つ目は「参照渡し」です。これは有効な概念ですが、これは 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");

の refcount$book1は 1 で、参照としてマークされていません。これを参照として$bookshelf1->addBook($book1)メソッドに渡すと、refcount が 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");

常に - ループごとに 1 回 - 同じ変数名でのみ新しいエイリアス (参照) を作成します。これを参照として渡すため、参照として割り当てる新しいエイリアスになります。したがって、Book内の配列は、同じ参照を 3 回ではなく、3 つの異なる参照を指します。

これで問題がよりよく説明されることを願っています。また、これが私たちが言う理由です:自分が何をしているのかを理解していない限り、参照を使用しないでください. PHP 4 の状況では、多くのユーザーが参照の仕組みを完全に理解せずに参照を使用していました (これは PHP では簡単ではないため理解できます。ここで共有する適切な説明が見つかるまで、少し頭を悩ませる必要があります。うまくいけば、今回はうまくいきました:))。ここで PHP 5 を使用する利点は、オブジェクトに対して参照を使用する必要がなくなることです。これにより、コードの記述と読み取りが容易になります。


関連している:

于 2013-05-11T08:56:08.780 に答える