"Phạm vi biến" là gì?
Các biến có một "phạm vi" giới hạn hoặc "những nơi mà chúng có thể truy cập được". Chỉ vì bạn đã viết $foo = 'bar';
một lần ở đâu đó trong ứng dụng của mình không có nghĩa là bạn có thể tham khảo $foo
từ mọi nơi khác trong ứng dụng. Biến $foo
có một phạm vi nhất định trong đó nó là hợp lệ và chỉ có mã trong cùng phạm vi có quyền truy cập vào biến.
Làm thế nào là một phạm vi được định nghĩa trong PHP?
Rất đơn giản: PHP có phạm vi chức năng . Đó là loại phân cách phạm vi duy nhất tồn tại trong PHP. Các biến bên trong một hàm chỉ có sẵn bên trong hàm đó. Các biến bên ngoài các hàm có sẵn ở bất kỳ đâu ngoài các hàm, nhưng không nằm trong bất kỳ hàm nào. Điều này có nghĩa là có một phạm vi đặc biệt trong PHP: toàn cầu phạm vi . Bất kỳ biến nào được khai báo bên ngoài bất kỳ chức năng nào đều nằm trong phạm vi toàn cầu này.
Thí dụ:
<?php
$foo = 'bar';
function myFunc() {
$baz = 42;
}
$foo
là trong phạm vi toàn cầu , $baz
là trong một phạm vi địa phương bên trong myFunc
. Chỉ có mã bên trong myFunc
có quyền truy cập $baz
. Chỉ có mã bên ngoài myFunc
có quyền truy cập $foo
. Không có quyền truy cập khác:
<?php
$foo = 'bar';
function myFunc() {
$baz = 42;
echo $foo; // doesn't work
echo $baz; // works
}
echo $foo; // works
echo $baz; // doesn't work
Phạm vi và tập tin bao gồm
Ranh giới tệp không tách phạm vi:
a.php
<?php
$foo = 'bar';
b.php
<?php
include 'a.php';
echo $foo; // works!
Các quy tắc tương tự áp dụng cho include
mã d như áp dụng cho bất kỳ mã nào khác: chỉfunction
phạm vi riêng biệt. Với mục đích phạm vi, bạn có thể nghĩ đến việc bao gồm các tệp như sao chép và dán mã:
c.php
<?php
function myFunc() {
include 'a.php';
echo $foo; // works
}
myFunc();
echo $foo; // doesn't work!
Trong ví dụ trên, a.php
được bao gồm bên trong myFunc
, bất kỳ biến nào bên trong a.php
chỉ có phạm vi hàm cục bộ. Chỉ vì chúng xuất hiện như nằm trong phạm vi toàn cầu a.php
không có nghĩa là chúng thực sự có nghĩa, nó thực sự phụ thuộc vào bối cảnh mà mã được bao gồm / thực thi trong bối cảnh nào.
Điều gì về các chức năng bên trong các chức năng và các lớp?
Mỗi cái mới function
tuyên bố giới thiệu một phạm vi mới, nó đơn giản.
(ẩn danh) các chức năng bên trong các chức năng
function foo() {
$foo = 'bar';
$bar = function () {
// no access to $foo
$baz = 'baz';
};
// no access to $baz
}
các lớp học
$foo = 'foo';
class Bar {
public function baz() {
// no access to $foo
$baz = 'baz';
}
}
// no access to $baz
Phạm vi tốt cho là gì?
Xử lý các vấn đề phạm vi có vẻ khó chịu, nhưng phạm vi biến hạn chế là điều cần thiết để viết các ứng dụng phức tạp! Nếu mọi biến bạn khai báo sẽ có sẵn từ mọi nơi khác trong ứng dụng của bạn, bạn sẽ bước qua tất cả các biến của mình mà không có cách nào thực sự để theo dõi những gì thay đổi những gì. Chỉ có rất nhiều tên hợp lý bạn có thể đặt cho các biến của mình, có lẽ bạn muốn sử dụng biến "$name
" ở nhiều nơi. Nếu bạn chỉ có thể có tên biến duy nhất này một lần trong ứng dụng của mình, bạn sẽ phải sử dụng các lược đồ đặt tên thực sự phức tạp để đảm bảo các biến của bạn là duy nhất và bạn không thay đổi biến sai từ đoạn mã sai.
Quan sát:
function foo() {
echo $bar;
}
Nếu không có phạm vi, chức năng trên sẽ làm gì? Nơi nào $bar
đến từ đâu? Nó có trạng thái gì? Nó thậm chí còn được khởi tạo? Bạn có phải kiểm tra mỗi lần? Điều này là không thể duy trì. Điều này đưa chúng ta đến ...
Vượt qua ranh giới phạm vi
Đúng cách: truyền biến vào và ra
function foo($bar) {
echo $bar;
return 42;
}
Biến $bar
rõ ràng là đi vào phạm vi này như là đối số chức năng. Chỉ cần nhìn vào chức năng này, rõ ràng các giá trị mà nó hoạt động bắt nguồn từ đâu. Sau đó, nó trả về một giá trị rõ ràng . Người gọi có thể tự tin để biết các biến mà hàm sẽ làm việc với và các giá trị trả về của nó đến từ đâu:
$baz = 'baz';
$blarg = foo($baz);
Mở rộng phạm vi của các biến thành các hàm ẩn danh
$foo = 'bar';
$baz = function () use ($foo) {
echo $foo;
};
$baz();
Hàm ẩn danh rõ ràng bao gồm $foo
từ phạm vi xung quanh của nó. Lưu ý rằng điều này không giống như toàn cầu phạm vi .
Cách sai: global
Như đã nói trước đây, phạm vi toàn cầu có phần đặc biệt và các hàm có thể nhập rõ ràng các biến từ nó:
$foo = 'bar';
function baz() {
global $foo;
echo $foo;
$foo = 'baz';
}
Hàm này sử dụng và sửa đổi biến toàn cục $foo
. Đừng làm điều này! (Trừ khi bạn thực sự thực sự thực sự thực sự biết những gì bạn đang làm, và thậm chí sau đó: không!)
Tất cả người gọi của chức năng này thấy là:
baz(); // outputs "bar"
unset($foo);
baz(); // no output, WTF?!
baz(); // outputs "baz", WTF?!?!!
Không có dấu hiệu cho thấy chức năng này có bất kỳ tác dụng phụ , nhưng nó có. Điều này rất dễ trở thành một mớ hỗn độn khi một số chức năng tiếp tục sửa đổi và yêu cầu một số trạng thái toàn cầu. Bạn muốn các chức năng không trạng thái , chỉ hoạt động trên đầu vào của chúng và trả về đầu ra được xác định, tuy nhiên nhiều lần bạn gọi chúng.
Bạn nên tránh sử dụng phạm vi toàn cầu theo bất kỳ cách nào càng nhiều càng tốt; chắc chắn bạn không nên "kéo" các biến ra khỏi phạm vi toàn cầu vào phạm vi cục bộ.