Làm cách nào để sử dụng tham chiếu trong PHP?

Trong bài viết này, tôi sẽ nói về cách các tham chiếu đối tượng và biến được kiểm soát trong bộ nhớ, vì đây là một vấn đề có thể tạo ra các cuộc thảo luận và ý kiến ​​khác nhau. Một câu hỏi để suy ngẫm là. “Theo mặc định, các đối tượng được truyền bằng tham chiếu hoặc bằng bản sao trong PHP?”

Qua

Agustin Villalba

Augustin là một kỹ sư PHP full-stack được Zend chứng nhận với hơn 10 năm kinh nghiệm tại các tổ chức như FIFA và Phòng thí nghiệm Sinh học Phân tử Châu Âu

CHIA SẺ

CHIA SẺ

Lần đầu tiên tôi soạn thảo bài viết này khi đang học để lấy chứng chỉ PHP nhằm nỗ lực hiểu rõ hơn cách PHP quản lý các biến và đối tượng trong bộ nhớ. Sau khi nghiên cứu rất nhiều, tôi nhận ra rằng không dễ để tìm ra câu trả lời cho câu hỏi của mình, vì vậy sau khi hoàn thành, tôi quyết định ghi lại thông tin để mọi người có thể tìm thấy tất cả ở một nơi

Trong bài viết này, tôi sẽ nói về cách các tham chiếu đối tượng và biến được kiểm soát trong bộ nhớ, vì đây là một vấn đề có thể tạo ra các cuộc thảo luận và ý kiến ​​khác nhau. Một câu hỏi để suy ngẫm là. “Theo mặc định, các đối tượng được truyền bằng tham chiếu hoặc bằng bản sao trong PHP?”

PHP tạo các đối tượng trong bộ nhớ như thế nào khi thực hiện một câu lệnh như $a = new Foo();? . Tuy nhiên, điều quan trọng đối với các nhà phát triển PHP giỏi là phải biết và hiểu cách các biến và đối tượng được quản lý nội bộ trong quá trình thực thi ứng dụng của họ.

Objects and references in PHP memory and PHP garbage collection

Đối tượng và tham chiếu trong PHP

Nhiều người nói—trong sách PHP và trên mạng—rằng các đối tượng trong PHP được chuyển theo tham chiếu theo mặc định. Những người khác nói rằng các đối tượng trong PHP được phân bổ theo bản sao. Để tìm ra câu nào đúng, trước tiên chúng ta phải phân tích cái gì là (và cái gì không) là tham chiếu trong PHP

Điều gì không phải là tài liệu tham khảo trong PHP?

Quan trọng hơn việc biết những tham chiếu nào trong PHP là biết chúng không phải là gì. Trong PHP, tham chiếu không phải là con trỏ kiểu C; . Tại sao? . Nhưng sau đó, tài liệu tham khảo là gì?

Tài liệu tham khảo trong PHP là gì?

Trong PHP, tham chiếu là “bí danh” cho phép hai biến khác nhau đọc và ghi một giá trị. Nói cách khác, chúng là các cơ chế cho phép truy cập vào cùng một giá trị từ các biến có tên khác nhau để chúng hoạt động như thể chúng là cùng một biến. Hãy nhớ rằng trong PHP, tên biến và nội dung của biến là hai thứ hoàn toàn khác nhau, được liên kết với nhau trong cái được gọi là “bảng ký hiệu”. ” Vì vậy, khi chúng ta tạo một tham chiếu, nó chỉ cần thêm một bí danh cho biến đó trong bảng ký hiệu. Giả sử chúng ta có đoạn mã sau

$a = new Foo();

Khi câu lệnh trên được thực thi, biến $a được tạo trong bộ nhớ, một đối tượng kiểu Foo được tạo trong bộ nhớ và một mục nhập được thêm vào bảng ký hiệu chỉ ra rằng biến $a “tham chiếu” (hoặc có liên quan đến, hoặc . Về mặt khái niệm, chúng tôi có một cái gì đó giống như hình minh họa này

Object references in PHP memory

Bài kiểm tra nhỏ bất ngờ. Điều gì xảy ra nếu chúng ta thực hiện điều này?

$b = $a;

Không phải là

$b = $a;
2 trở thành tham chiếu của $a; . Điều thực sự xảy ra là chúng ta đã tạo một biến mới
$b = $a;
2 trong bộ nhớ và sau đó thêm một mục mới vào bảng ký hiệu chỉ ra rằng biến
$b = $a;
2 cũng tham chiếu đến cùng một đối tượng Foo$a không. Vì vậy, trực quan, chúng tôi có một cái gì đó tương tự như những gì nó được hiển thị trong hình minh họa này

Object references in PHP memory

Bây giờ, nếu chúng ta thực hiện

$c = &$a;

Chúng tôi sẽ tạo một biến thứ ba

$c = &$a;
0 trong bộ nhớ, nhưng không phải là một mục mới trong bảng ký hiệu cho
$c = &$a;
0. Thay vào đó, trong bảng ký hiệu, nó được ghi lại rằng
$c = &$a;
0 là bí danh của $a, vì vậy nó sẽ hoạt động giống hệt nhau, nhưng
$c = &$a;
0 không phải là con trỏ tới $a—không giống như trong C, cái này tạo ra thứ gọi là con trỏ tới con trỏ. Để hình dung, chúng ta có một cái gì đó tương tự như trong hình minh họa này

Diagram of variables and their aliases

Ngay khi chúng tôi muốn sửa đổi giá trị của bất kỳ biến nào trong ba biến này (i. e. , viết một giá trị mới), PHP sẽ phải tạo một cấu trúc

$c = &$a;
6 mới trong bộ nhớ để tách nội dung của biến
$b = $a;
2 và cặp $a/
$c = &$a;
0 để chúng có thể được sửa đổi một cách độc lập mà không ảnh hưởng đến giá trị của biến kia. Vì vậy, nếu chúng ta thêm dòng sau vào tập lệnh trước

$b = new Bar();

Trong bộ nhớ, chúng ta sẽ có một tình huống như minh họa trong hình sau

Graphic representation of the situation described above

Bây giờ, hãy xem xét một ví dụ đầy đủ hơn

<?php

class myClass {
    public $var;
		
    function __construct() {
	$this->var = 1;
    }

    function inc() { return ++$this->var; }
}

$a = new myClass(); // $a "references" a Foo object
$b = $a; //b also references the same Foo object as a
//($a) == ($b) == <id> of Foo object, but a and b are different entries in symbols table

echo "$a = ";var_dump($a);
echo "$b = ";var_dump($b);

$c = &$a; //$c is an alias of $a
//($a, $c) == <id> of Foo object, c is an alias of a in the symbols table
echo "$c = ";var_dump($c);

$a = NULL;
//The entry in the symbols table which links "$a" with Foo object is removed
//Since that entry was removed, $c is not related to Foo anymore
//Anyway, Foo still exists in memory and it is still linked by $b
echo "$a = ";var_dump($a);
echo "$b = ";var_dump($b);
echo "$c = ";var_dump($c);
echo "$b->var: ".$b->inc();
echo "$b->var: ".$b->inc();

$b = NULL;
//The entry in the symbols table which links "$b" with the Foo object is removed
//There are no more entries in the symbols table linked to Foo,
//So, Foo is not referenced anymore and can be deleted by the garbage collector

echo "$b = ";var_dump($b);

Đầu ra được tạo bởi việc triển khai tập lệnh trên là

$a = object(myClass)#1 (1) { ["var"]=> int(1) } 
$b = object(myClass)#1 (1) { ["var"]=> int(1) } 

$c = object(myClass)#1 (1) { ["var"]=> int(1) } 
$a = NULL 
$b = object(myClass)#1 (1) { ["var"]=> int(1) } 
$c = NULL 
$b->var: 2
$b->var: 3

$b = NULL

Bộ sưu tập rác PHP

Cuối cùng, hãy xem cách bộ sưu tập rác PHP hoạt động, vì nó đã được giới thiệu trong phiên bản 5. 3. Một đối tượng hoặc biến trong bộ nhớ PHP sẽ bị bộ thu gom rác PHP xóa khi không có tham chiếu đến đối tượng đó trong bảng ký hiệu. Tức là, PHP duy trì một bộ đếm tham chiếu của một đối tượng ngay từ khi nó được tạo để trong quá trình thực thi tập lệnh PHP, bộ đếm sẽ tăng và giảm bộ đếm tham chiếu đó dựa trên các biến đang “trỏ” tới nó. Khi số lượng tham chiếu đạt đến 0 (i. e. , không có gì tham chiếu đến đối tượng đó và do đó, nó không được sử dụng), PHP đánh dấu đối tượng đó là có thể tháo rời, để trong lần tiếp theo của trình thu gom rác PHP, nó sẽ bị xóa khỏi bộ nhớ, giải phóng không gian đó để sử dụng lại. Nếu bạn muốn biết thêm chi tiết chuyên sâu về cách hoạt động của bộ sưu tập rác PHP, hãy đọc tài liệu này

Bớt tư tưởng

Tôi hy vọng tôi đã làm rõ một chút cách PHP xử lý các đối tượng và biến trong bộ nhớ và cách nó “chọn” các đối tượng cần được loại bỏ bởi trình thu gom rác PHP

Bây giờ bạn đã hiểu cách PHP quản lý các biến và đối tượng trong bộ nhớ bên trong, hãy lấy máy tính xách tay của bạn và bắt đầu thử nghiệm một số mã để chứng minh những gì bạn đã học. Hãy thử chơi xung quanh với các biến và tham chiếu. Ngoài ra, hãy thử nghiệm xem việc thay đổi giá trị của một biến có thể ảnh hưởng như thế nào đến giá trị của biến khác tham chiếu đến nó. Đây là một câu hỏi dành cho bạn. Giá trị của $a

$b = $a;
2 sau khi mã bên dưới được thực thi là gì?

$a = '1';
$b = &$a;
$b = "2$b";

Nếu bạn muốn đọc thêm về các tính năng hiệu suất của PHP, hãy xem bài đăng này của đồng nghiệp Toptaler Vilson Duka

Hiểu những điều cơ bản

Tài liệu tham khảo trong PHP là gì?

Trong PHP, tham chiếu là “bí danh” cho phép hai biến khác nhau đọc và ghi một giá trị

Bộ sưu tập rác PHP hoạt động như thế nào?

PHP duy trì số lượng tham chiếu tới một đối tượng từ thời điểm nó được tạo. Khi không có tham chiếu đến đối tượng đó trong bảng ký hiệu, trình thu gom rác PHP sẽ loại bỏ nó

Các tham chiếu bộ nhớ PHP được lưu trữ như thế nào?

Các tham chiếu bộ nhớ PHP được lưu trữ trong kho lưu trữ khóa-giá trị được gọi là bảng ký hiệu

Thẻ

PHPGarbageCollectionMemoryReferences

Người làm việc tự do? Tìm công việc tiếp theo của bạn.

Việc làm Lập trình viên PHP

Xem thông tin đầy đủ

Agustin Villalba

Nhà phát triển PHP tự do

Thông tin về các Tác giả

Agustin là một nhà phát triển web với 12 năm kinh nghiệm phát triển các ứng dụng web full-stack. Ông đi đầu trong việc phát triển một dự án web cho Ban trọng tài FIFA và phát triển cho Phòng thí nghiệm sinh học phân tử châu Âu (www. huy hiệu. de). Anh ấy cũng là một Zend PHP 5. 3 Kỹ sư được chứng nhận

Thuê Agustin

Bình luận

Usama Ahmed

Tôi mất chưa đầy 3 giây để tìm hiểu cách php quản lý các đối tượng. Hướng dẫn chính thức của PHP có rất nhiều tài liệu về nó. Toptal có buộc bạn phải xây dựng bài viết từ tìm kiếm trên google không?

Usama Ahmed

Tôi mất chưa đầy 3 giây để tìm hiểu cách php quản lý các đối tượng. Hướng dẫn chính thức của PHP có rất nhiều tài liệu về nó. Toptal có buộc bạn phải xây dựng bài viết từ tìm kiếm trên google không?

Zbynek

con trỏ và tham chiếu trong c không giống nhau, int a = 1; . trong php không có con trỏ, nhưng có các tham chiếu như trong c và chúng hoạt động chủ yếu giống như trong c, vì vậy bạn không nên so sánh con trỏ c với tham chiếu php, điều đó không có ý nghĩa

Zbynek

con trỏ và tham chiếu trong c không giống nhau, int a = 1; . trong php không có con trỏ, nhưng có các tham chiếu như trong c và chúng hoạt động chủ yếu giống như trong c, vì vậy bạn không nên so sánh con trỏ c với tham chiếu php, điều đó không có ý nghĩa

Agustín

Xin chào Zbynek, Cảm ơn bạn đã bình luận. Chính xác thì con trỏ và tham chiếu không giống nhau, đó là những gì chúng tôi nêu trong bài viết. Ngoài ra, như bạn đã đề cập, chúng tôi giải thích rằng không giống như con trỏ C, các tham chiếu PHP không phải là địa chỉ bộ nhớ, vì vậy phép so sánh được sử dụng để nhận xét rằng chúng không giống nhau;)

Agustín

Xin chào Zbynek, Cảm ơn bạn đã bình luận. Chính xác thì con trỏ và tham chiếu không giống nhau, đó là những gì chúng tôi nêu trong bài viết. Ngoài ra, như bạn đã đề cập, chúng tôi giải thích rằng không giống như con trỏ C, các tham chiếu PHP không phải là địa chỉ bộ nhớ, vì vậy phép so sánh được sử dụng để nhận xét rằng chúng không giống nhau;)

Zbynek

bạn đang nghĩ vậy thì có ai đó nghĩ tham chiếu php là con trỏ C không?

Zbynek

bạn đang nghĩ vậy thì có ai đó nghĩ tham chiếu php là con trỏ C không?

Agustín

Tôi thực sự nghi ngờ rằng bạn có thể tìm thấy thông tin chi tiết và được giải thích rõ ràng về nội bộ PHP trong 3 giây. Mặc dù tài liệu PHP thường tốt, nhưng điều đó không có nghĩa là mọi người đều có "chuyên môn" của bạn để hiểu nó. Bài đăng này được thực hiện dựa trên nghiên cứu và tài liệu riêng, vì vậy nếu bạn không thích nó thì cũng tốt thôi (tất nhiên rồi. ), nhưng bình luận của bạn không thêm bất kỳ thảo luận hoặc tranh luận nào về chủ đề này, vì vậy không có nhiều điều để trả lời. ;)

Agustín

Tôi thực sự nghi ngờ rằng bạn có thể tìm thấy thông tin chi tiết và được giải thích rõ ràng về nội bộ PHP trong 3 giây. Mặc dù tài liệu PHP thường tốt, nhưng điều đó không có nghĩa là mọi người đều có "chuyên môn" của bạn để hiểu nó. Bài đăng này được thực hiện dựa trên nghiên cứu và tài liệu riêng, vì vậy nếu bạn không thích nó thì cũng tốt thôi (tất nhiên rồi. ), nhưng bình luận của bạn không thêm bất kỳ thảo luận hoặc tranh luận nào về chủ đề này, vì vậy không có nhiều điều để trả lời. ;)

Lars Moelleken

Heyho, đây là một nhận xét mang tính xây dựng hơn một chút ;-) Nếu bạn chạy tập lệnh php sau, bạn có thể chỉ cần xem các tham chiếu và sao chép khi ghi đang hoạt động như thế nào. bắt đầu. mảng 88 byte. 8524592 byte chức năng1-bắt đầu. 8524608 byte chức năng1-end. 17049016 byte mảng-test4. 8524536 byte chức năng2-bắt đầu. 8524552 byte chức năng2-end. 8524616 byte mảng-test4_ref. 8524552 byte kết thúc. 8524552 byte https. //github. com/voku/php_zval_test/blob/master/test4. php

Lars Moelleken

Heyho, đây là một nhận xét mang tính xây dựng hơn một chút ;-) Nếu bạn chạy tập lệnh php sau, bạn có thể chỉ cần xem các tham chiếu và sao chép khi ghi đang hoạt động như thế nào. bắt đầu. mảng 88 byte. 8524592 byte chức năng1-bắt đầu. 8524608 byte chức năng1-end. 17049016 byte mảng-test4. 8524536 byte chức năng2-bắt đầu. 8524552 byte chức năng2-end. 8524616 byte mảng-test4_ref. 8524552 byte kết thúc. 8524552 byte https. //github. com/voku/php_zval_test/blob/master/test4. php

Mladen Janjetovic

Điều này hoàn toàn không đúng, tôi đã cố gắng tìm một thứ được giải thích rõ ràng như thế này và tôi đã mất một lúc

Mladen Janjetovic

Điều này hoàn toàn không đúng, tôi đã cố gắng tìm một thứ được giải thích rõ ràng như thế này và tôi đã mất một lúc

Neda Abbasi

Cách gán bộ nhớ cho các biến trong php?

Neda Abbasi

Cách gán bộ nhớ cho các biến trong php?

OAH

đừng có ghét như vậy. Viết gì tầm cỡ này nọ rồi “khoe”. Cảm ơn các bác trong toptal vì bài viết rất hay này. Giữ công việc tốt Agustin

OAH

Bây giờ đó là một số thứ nghiêm trọng ở đây. Kết hợp điều này với bài đăng tuyệt vời từ stackoverflow trên mảng php "sao chép khi ghi" làm cho bộ nhớ mgmt trong php trở nên dễ nắm bắt hơn rất nhiều. Cảm ơn mọi người

Làm cách nào để cung cấp tài liệu tham khảo trong PHP?

Trong PHP, tên biến và nội dung biến khác nhau nên cùng một nội dung có thể có tên khác nhau. Biến tham chiếu được tạo bằng cách tiền tố & ký hiệu cho biến ban đầu . Do đó b=&a sẽ có nghĩa là bisareferewncevariableofa.

Khi nào sử dụng tham chiếu trong PHP?

Câu trả lời ngắn gọn là sử dụng tài liệu tham khảo khi bạn cần chức năng mà họ cung cấp . Đừng nghĩ về chúng về mặt sử dụng bộ nhớ hoặc tốc độ. Truyền theo tham chiếu sẽ luôn chậm hơn nếu biến chỉ được đọc. Mọi thứ được truyền theo giá trị, bao gồm cả các đối tượng.

Bạn có nên chuyển qua tham chiếu trong PHP không?

Vì vậy, hãy sử dụng tham chiếu chuyển tiếp bất cứ khi nào bạn muốn một hàm thay đổi một biến được truyền cho nó . Đơn giản. Nhân tiện, đừng cố gắng đặt dấu và trước tên đối số trong lời gọi hàm của bạn. tạm biệt( &$myVar ); .

Làm cách nào để chuyển mảng theo tham chiếu trong PHP?

Đây là một tập lệnh PHP về cách chuyển mảng làm tham chiếu.