30/09/2018, 23:59

Objects and references in PHP

E đang học PHP trên trang PHP.Net, đọc đến cái bài Objects and references in PHP đọc mãi mà ko thông não đc, ai pro giải đáp giúp e với ạ
A PHP reference is an alias, which allows two different variables to write to the same value. As of PHP 5, an object variable doesn’t contain the object itself as value anymore. It only contains an object identifier which allows object accessors to find the actual object. When an object is sent by argument, returned or assigned to another variable, the different variables are not aliases: they hold a copy of the identifier, which points to the same object.
Đoạn này nó nói là tham chiếu trong PHP là 1 tên giả cho phép 2 biến có cùng 1 giá trị đoạn này thì e hiểu là truyền tham chiếu vd $a = &$b tức là $a chỉ là tên giả của $b cả 2 cùng là một. Còn đoạn sau e dốt tiếng anh nên ko hiểu nó nói cái gì. Xem ví dụ của nó thì như này

class A {
    public $foo = 1;
}  

$a = new A;
$b = $a;     // $a and $b are copies of the same identifier
             // ($a) = ($b) = <id>
$b->foo = 2;
echo $a->foo."
";
$c = new A;
$d = &$c;    // $c and $d are references
             // ($c,$d) = <id>

E ko hiểu lắm “copies of the same identifier” vs “references” nó khác nhau chỗ nào. Ở TH1 thì thay đổi giá trị a->b thay đổi theo và ngược lại, ở TH2 cũng tương tự thay đổi giá trị 1 trong 2 cái thì cái ngược lại cũng thay đổi theo thì sự khác biệt ở đây là gì. Ở phần comment cũng có đoạn như này

A reference is not a pointer. However, an object handle IS a pointer. Example:

Đại loại e hiểu là tham chiếu ko phải 1 con trỏ, tuy nhiên 1 object handle là 1 con trỏ thì ai giải thích cho e object handle nó là cái gì đc ko? tại xem ví dụ của nó cũng ko hiểu

$a = new Foo; // $a is a pointer pointing to Foo object 0
$b = $a; // $b is a pointer pointing to Foo object 0, however, $b is a copy of $a
$a là một con trỏ trỏ đến đối tượng Foo 0 rồi $b là một con trỏ trỏ đến đối tượng Foo 0, tuy nhiên $b là copy của $a 
( ko hiểu chỗ này, copy vs trỏ nó khác nhau chỗ nào)

$c = &$a; // $c and $a are now references of a pointer pointing to Foo object 0
$a = new Foo; // $a and $c are now references of a pointer pointing to Foo object 1, $b is still a pointer pointing to Foo object 0

(ko hiểu chỗ này, tham chiếu của con trỏ trỏ đến đối tượng Foo 0 là cái gì, đoạn dưới là $a và $c là tham chiếu của con trỏ Foo 1, còn $b vẫn là con trỏ trỏ đến đối tượng Foo 0 thì tham chiếu của con trỏ khác con trỏ chỗ nào)

Trc h học C thì mặc định tham chiếu giống vs con trỏ đều là địa chỉ ô nhớ giờ sang đây nó phân biệt 2 cái e ko hiểu lắm nó khác nhau chỗ nào, rồi có tài liệu bảo tham chiếu trong PHP là con trỏ có tài liệu lại bảo trong PHP tham chiếu ko phải là con trỏ. Ai rảnh + pro thì giải thích giùm e mấy vấn đề trên vs :(( giải thích đc từng dòng code 1 thì càng tốt ạ. Here’s the code

<?php
class Foo {
  private static $used;
  private $id;
  public function __construct() {
    $id = $used++;
  }
  public function __clone() {
    $id = $used++;
  }
}

$a = new Foo; // $a is a pointer pointing to Foo object 0
$b = $a; // $b is a pointer pointing to Foo object 0, however, $b is a copy of $a
$c = &$a; // $c and $a are now references of a pointer pointing to Foo object 0
$a = new Foo; // $a and $c are now references of a pointer pointing to Foo object 1, $b is still a pointer pointing to Foo object 0
unset($a); // A reference with reference count 1 is automatically converted back to a value. Now $c is a pointer to Foo object 1
$a = &$b; // $a and $b are now references of a pointer pointing to Foo object 0
$a = NULL; // $a and $b now become a reference to NULL. Foo object 0 can be garbage collected now
unset($b); // $b no longer exists and $a is now NULL
$a = clone $c; // $a is now a pointer to Foo object 2, $c remains a pointer to Foo object 1
unset($c); // Foo object 1 can be garbage collected now.
$c = $a; // $c and $a are pointers pointing to Foo object 2
unset($a); // Foo object 2 is still pointed by $c
$a = &$c; // Foo object 2 has 1 pointers pointing to it only, that pointer has 2 references: $a and $c;
const ABC = TRUE;
if(ABC) {
  $a = NULL; // Foo object 2 can be garbage collected now because $a and $c are now a reference to the same NULL value
} else {
  unset($a); // Foo object 2 is still pointed to $c
}
Đinh Quốc Hân viết 02:02 ngày 01/10/2018

Bạn chèn code nhìn hơi rối mắt, bạn xem bài sau để biết cách chèn code vào bài viết nhé.

Làm sao để có thể hiển thị syntax highlighting bằng markdown? Các bạn phải đánh dấu ``` như ví dụ dưới đây Chú ý, dấu ``` được tạo ra bởi nút nằm bên trái số 1 trên bàn phím, nút này sẽ là ~ khi bấm giữ Shift Ví dụ cho C Nội dung: ``` void main() { } ``` Và đừng quên ``` ở cuối Kết quả void main() { } Ví dụ cho Pascal Nội dung: ``` Program HelloWorld; Begin WriteLn('Hello world!') {no ";" is required after the last statement of a block - adding one adds a "null stateme…
Thanh Phong viết 02:13 ngày 01/10/2018

ok thanks bạn, tại mới biết diễn đàn này nên chưa biết nhiều lắm, sẽ rút kinh nghiệm lần sau

Đinh Quốc Hân viết 02:15 ngày 01/10/2018

Sự khác biệt chỉ cần đưa ra một ví dụ là bạn sẽ hiểu ngay mình đưa ra ví dụ nhé:


<?php

class Sample {
     public $foo = 'default';
}

$a = new Sample;
$b = $a;
$c =& $a;

$a->foo = 'new a';

print_r($a->foo); // new a
print_r($b->foo); // new a, a copy
print_r($c->foo); // new a, not copy it's $a
Thanh Phong viết 02:07 ngày 01/10/2018

Cả 3 cái đều là new a mà bạn. Ở đoạn đầu nó viết “One of the key-points of PHP 5 OOP that is often mentioned is that “objects are passed by references by default”.” theo mình hiểu là object trong PHP mặc định đc truyền bởi tham chiếu nên là ko cần $b= &$a mà chỉ cần $b = $a là đc rồi, thay đổi giá trị 1 trong 2 là giá trị biến còn lại cũng thay đổi theo. Mà ở đoạn sau nó lại nói “This is not completely true. This section rectifies that general thought using some examples.” xong nó đưa đoạn code

class A {
    public $foo = 1;
}  

$a = new A;
$b = $a;     // $a and $b are copies of the same identifier
             // ($a) = ($b) = <id>
$b->foo = 2;
echo $a->foo."\n";
$c = new A;
$d = &$c;  

Mình test thấy cả 2 đều giống nhau thay đổi giá trị của 1 trong 2 cái thì 1 trong 2 cái còn lại thay đổi theo nên ms ko hiểu 2 đoạn này khác nhau chỗ nào

Đinh Quốc Hân viết 02:01 ngày 01/10/2018

À mình nhầm, tham chiếu trong PHP có nghĩa là có nghĩa là 1 biến chiếu đến vùng nhớ của 1 biến khác. 2 biến này dùng chung 1 vùng nhớ chứa giá trị nên khi dùng phép gán cho biến này thì giá trị của biến kia cũng thay đổi . Tham chiếu trong PHP có ký hiệu là dấu &

ví dụ:

<?php
  $a = 1;
  $b = $a;
  $b = 5;
  var_dump($a); // 1
  var_dump($b) // 5

nhưng khi

<?php
  $a = 1;
  $b = &$a;
  $b = 5;
  var_dump($a); // 5
  var_dump($b) // 5

Tuy nhiên


<?php

class Sample {
     public $foo = 'default';
}

$a = new Sample;
$b = $a;
$c =& $a;

$a->foo = 'new a';

print_r($a->foo); // new a
print_r($b->foo); // new a
print_r($c->foo); // new a

và mình nhớ không nhầm từ php 5 trở đi khi $a = $b nó sẽ tự động hiểu là $a = &$b chỉ khi $a là một đối tượng, và bắt buộc muốn có một object mới bắt buôc phải khởi tạo lại.

Phan Hoàng viết 02:01 ngày 01/10/2018

Thực ra phân biệt pointer và reference không cần thiết lắm nhưng có thể hiểu 1 chút như sau:

1- Reference (hay còn gọi là alias, nickname): Khi bạn dùng $c = &$a thì $c trở thành nickname của $a. Nickname này sẽ theo bạn đến hết cuộc đời y như name vậy, trừ phi bạn xóa và tạo mới nickname cho mình (decouple - chia rẽ name và nickname)

function change1(&$k){
    $k = new A();
    $k->foo++;
    echo $k->foo . "\n";
}

function change2($k){
    $k = new A();
    $k->foo++;
    echo $k->foo . "\n";
}

$a = new A();
change2($a); //ra 2
echo $a->foo . "\n"; //vẫn ra 1

change1($a); //ra 2
echo $a->foo . "\n"; //ra 2

Vậy đó, function change2 truyền gía trị ô nhớ (address) của pointer mà thôi, còn $k lúc này hoàn toàn có thể là 1 object mới, trong khi hàm change1 truyền alias/reference (nickname) nên giờ nó trở thành 1 cặp trời sinh rồi, trừ phi chia lìa thì nó mới không là nhau.

2- Khi bạn viết $a = new A(), nó sẽ tạo 1 object trong vùng nhớ heap, đồng thời tạo ra một pointer trỏ tới địa chỉ vùng nhớ này. Khởi tạo biến $a, nó sẽ gán $a = gía trị pointer vừa tạo. Thế nên $b = $a, cả 2 biến cùng hold gía trị vùng nhớ và cùng là pointer. TUy nhiên $c = &$a thì $c sẽ trở thành pointer alias của $a và $a cũng trở thành pointer alias của $c. Cũng như bạn tên là Đạt, bạn bè bạn gọi là Phít thì gọi Phít hay Đạt đều ok, Phít là nicknam của Đạt mà Đạt là nickname của Phít.

Bài liên quan
0