Cách tốt nhất để kiểm tra sự tồn tại của một biến trong PHP; Ngay lập tức () bị hỏng


187

Từ các isset()tài liệu :

isset() will return FALSE if testing a variable that has been set to NULL.

Về cơ bản, isset()không kiểm tra xem biến đó có được đặt hay không, nhưng liệu nó có được đặt thành bất cứ thứ gì không NULL.

Cho rằng, cách tốt nhất để thực sự kiểm tra sự tồn tại của một biến là gì? Tôi đã thử một cái gì đó như:

if(isset($v) || @is_null($v))

( @cần thiết để tránh cảnh báo khi $vkhông được đặt) nhưng is_null()có một vấn đề tương tự như isset(): nó trả TRUEvề các biến không đặt! Nó cũng xuất hiện rằng:

@($v === NULL)

hoạt động chính xác như @is_null($v)vậy, do đó, quá.

Làm thế nào chúng ta phải kiểm tra một cách đáng tin cậy sự tồn tại của một biến trong PHP?


Chỉnh sửa: rõ ràng có sự khác biệt về PHP giữa các biến không được đặt và các biến được đặt thành NULL:

<?php
$a = array('b' => NULL);
var_dump($a);

PHP cho thấy rằng $a['b']tồn tại và có một NULLgiá trị. Nếu bạn thêm:

var_dump(isset($a['b']));
var_dump(isset($a['c']));

bạn có thể thấy sự mơ hồ mà tôi đang nói về isset()chức năng này. Đây là đầu ra của cả ba điều này var_dump()s:

array(1) {
  ["b"]=>
  NULL
}
bool(false)
bool(false)

Chỉnh sửa thêm: hai điều.

Một, một trường hợp sử dụng. Một mảng được biến thành dữ liệu của câu lệnh SQL UPDATE, trong đó các khóa của mảng là các cột của bảng và các giá trị của mảng là các giá trị được áp dụng cho mỗi cột. Bất kỳ cột nào của bảng có thể giữ một NULLgiá trị, được biểu thị bằng cách chuyển một NULLgiá trị trong mảng. Bạn cần một cách để phân biệt giữa khóa mảng không tồn tại và giá trị của mảng được đặt thànhNULL ; đó là sự khác biệt giữa việc không cập nhật giá trị của cột và cập nhật giá trị của cột thành NULL.

Thứ hai, câu trả lời của Zoredache , array_key_exists()hoạt động chính xác, cho trường hợp sử dụng ở trên của tôi và cho bất kỳ biến toàn cục nào:

<?php
$a = NULL;
var_dump(array_key_exists('a', $GLOBALS));
var_dump(array_key_exists('b', $GLOBALS));

đầu ra:

bool(true)
bool(false)

Vì điều đó xử lý đúng cách ở mọi nơi tôi có thể thấy có bất kỳ sự mơ hồ nào giữa các biến không tồn tại và các biến được đặt thành NULL, tôi đang gọiarray_key_exists() cách dễ nhất chính thức trong PHP để thực sự kiểm tra sự tồn tại của biến .

(Chỉ có trường hợp khác tôi có thể nghĩ là dành cho các thuộc tính lớp property_exists(), theo đó, theo tài liệu của nó , hoạt động tương tự như array_key_exists()ở chỗ nó phân biệt chính xác giữa không được đặt và được đặt thành NULL.)


Bạn không thể kiểm tra - nhưng tại sao bạn cần phải làm thế?
quá nhiều php

12
NULL có một ý nghĩa rất cụ thể trong PHP và đó là một khái niệm hoàn toàn tách biệt với việc một biến có được đặt hay không.
chazomaticus

33
Có nhiều lý do để phân biệt giữa null và không tồn tại. Ví dụ: bạn đang xây dựng một đối tượng để thể hiện một hàng trong bảng cơ sở dữ liệu. Đối với mỗi cột trong hàng, bạn tạo một biến riêng tư, chỉ có thể truy cập thông qua phương thức getter của đối tượng. Giả sử một giá trị cột là null. Bây giờ làm thế nào để phương thức getter đó biết liệu không có cột nào như vậy trong bảng hay liệu đối tượng này chỉ có giá trị null ở đó? May mắn thay, trong trường hợp của tôi, biến riêng tư thực sự là một mục trong một mảng riêng tư, vì vậy tôi có thể sử dụng mảng_key_exists, nhưng đây là một vấn đề thực sự.
Nathan Long

1
Nó đã bị xóa khỏi các phiên bản mới của PHP, vâng. Thật không may, nó không đi từ mọi triển khai PHP. Ngoài ra, nó có vẻ như là một chi tiết ngữ nghĩa vô nghĩa để ngụy biện về việc chúng ta đang nói về các phần tử mảng hay biến. Bất kể tiêu chuẩn nào bạn nghĩ rằng mã phải tuân thủ, thật hữu ích khi biết cách khắc phục sự không nhất quán trong ngôn ngữ PHP.
chazomaticus

2
@chazomaticus Nhưng các biến và các thành phần mảng là những thứ khác nhau cơ bản ; chỉ vì bạn có thể thực hiện một số điều tương tự với chúng không có nghĩa là chúng có thể hoặc có thể hoán đổi cho nhau 100%. Không có "sự không nhất quán trong ngôn ngữ PHP" ở đây, chỉ là điều bạn không thích / hiểu. Về phần register_globals, tôi vẫn đang cố gắng nghĩ về một tình huống mà thậm chí sẽ yêu cầu sự khác biệt như vậy, vì bất kỳ thứ gì được đăng ký từ yêu cầu HTTP sẽ luôn luôn là một chuỗi, không phải null.
IMSoP

Câu trả lời:


97

Nếu biến bạn đang kiểm tra sẽ nằm trong phạm vi toàn cầu bạn có thể làm:

array_key_exists('v', $GLOBALS) 

3
À ha! NGAY BÂY GIỜ bạn đang nói chuyện! Làm thế nào bạn sẽ làm điều đó cho, nói, thuộc tính lớp?
chazomaticus

22
Là một biến thể, nếu kiểm tra cũng cần phải làm việc với các biến phạm vi cục bộ, thì có thể thực hiện $defined_vars = get_defined_vars();và sau đó kiểm tra thông qua array_key_exists('v', $defined_vars);.
Henrik Opel

1
Điều này có vẻ hơi xấu đối với tôi, nhưng trong trường hợp bạn thực sự kiểm tra một phần tử mảng, nó có ý nghĩa hơn nhiều: isset($foo[$bar])trở thànharray_key_exists($bar, $foo)
Arild

property_existscó vẻ đầy hứa hẹn, ngoại trừ điều này:> Hàm property_exists () không thể phát hiện các thuộc tính có thể truy cập một cách kỳ diệu bằng phương thức ma thuật __get.
alexw

@alexw Biến "được tạo" thông qua __get thực sự không tồn tại. __get là mã tùy ý được sử dụng làm dự phòng cho các biến không tồn tại, có thể trả về bất cứ thứ gì nó muốn bất kể dữ liệu có liên quan đã được lưu trữ hay không.
Brilliand

46

Cố gắng đưa ra một cái nhìn tổng quan về các cuộc thảo luận và câu trả lời khác nhau:

Không có câu trả lời duy nhất cho câu hỏi có thể thay thế tất cả các cách issetcó thể được sử dụng. Một số trường hợp sử dụng được giải quyết bởi các chức năng khác, trong khi các trường hợp khác không chịu sự giám sát, hoặc có giá trị đáng ngờ ngoài mã golf. Khác xa với việc "bị hỏng" hoặc "không nhất quán", các trường hợp sử dụng khác chứng minh tại sao issetphản ứng của nó đối vớinull là hành vi logic.

Các trường hợp sử dụng thực tế (có giải pháp)

1. Phím mảng

Mảng có thể được coi như tập hợp các biến, với unsetissetxử lý chúng như thể chúng là. Tuy nhiên, vì chúng có thể được lặp đi lặp lại, được tính, v.v., nên một giá trị bị thiếu không giống với giá trị lànull .

Câu trả lời trong trường hợp này là sử dụng array_key_exists()thay vìisset() .

Vì đây là mảng để kiểm tra làm đối số hàm, PHP vẫn sẽ đưa ra "thông báo" nếu mảng đó không tồn tại. Trong một số trường hợp, có thể lập luận một cách hợp lệ rằng mỗi chiều nên được khởi tạo trước, vì vậy thông báo đang thực hiện công việc của nó. Đối với các trường hợp khác, một hàm "đệ quy" array_key_exists, lần lượt kiểm tra từng chiều của mảng, sẽ tránh điều này, nhưng về cơ bản sẽ giống như @array_key_exists. Nó cũng hơi tiếp xúc với việc xử lýnull giá trị.

2. Thuộc tính đối tượng

Trong lý thuyết truyền thống về "Lập trình hướng đối tượng", đóng gói và đa hình là các thuộc tính chính của các đối tượng; trong việc thực hiện OOP dựa trên lớp như PHP, các thuộc tính đóng gói được khai báo như là một phần của định nghĩa lớp, và cho cấp độ truy cập ( public, protectedhoặc private).

Tuy nhiên, PHP cũng cho phép bạn tự động thêm các thuộc tính vào một đối tượng, giống như bạn khóa các mảng và một số người sử dụng các đối tượng không có lớp (về mặt kỹ thuật, các phiên bản được xây dựng stdClass, không có phương thức hoặc chức năng riêng tư) tương tự cách để mảng kết hợp. Điều này dẫn đến các tình huống trong đó một chức năng có thể muốn biết nếu một thuộc tính cụ thể đã được thêm vào đối tượng được cung cấp cho nó.

Như với các khóa mảng, một giải pháp để kiểm tra các thuộc tính đối tượng được bao gồm trong ngôn ngữ, được gọi là, đủ hợp lý ,property_exists .

Các trường hợp sử dụng không chính đáng, có thảo luận

3. register_globalsvà ô nhiễm khác của không gian tên toàn cầu

Các register_globalstính năng bổ sung các biến với phạm vi toàn cầu có tên được xác định bởi các khía cạnh của yêu cầu HTTP (GET và POST thông số, và cookie). Điều này có thể dẫn đến mã lỗi và không an toàn, đó là lý do tại sao nó đã bị tắt theo mặc định kể từ PHP 4.2, phát hành tháng 8 năm 2000 và bị xóa hoàn toàn trong PHP 5.4, phát hành tháng 3 năm 2012 . Tuy nhiên, có thể một số hệ thống vẫn đang chạy với tính năng này được kích hoạt hoặc mô phỏng. Cũng có thể "gây ô nhiễm" không gian tên toàn cầu theo những cách khác, bằng cách sử dụng globaltừ khóa hoặc $GLOBALSmảng.

Thứ nhất, register_globalsbản thân không có khả năng bất ngờ tạo ra một nullbiến, vì GET, POST, và giá trị cookie sẽ luôn là chuỗi (với ''vẫn trở về truetừ isset), và các biến trong phiên giao dịch nên được hoàn toàn dưới sự kiểm soát của lập trình viên.

Thứ hai, ô nhiễm của một biến có giá trị nullchỉ là một vấn đề nếu điều này ghi đè lên một số khởi tạo trước đó. "Viết quá mức" một biến chưa được khởi tạo với nullsẽ chỉ có vấn đề nếu mã ở nơi khác phân biệt giữa hai trạng thái, do đó, khả năng này là một lập luận chống lại sự phân biệt như vậy.

4. get_defined_varscompact

Một vài hàm hiếm khi được sử dụng trong PHP, như get_defined_vars, và compactcho phép bạn xử lý các tên biến như thể chúng là các khóa trong một mảng. Đối với các biến toàn cục, mảng siêu toàn cầu$GLOBALS cho phép truy cập tương tự và phổ biến hơn. Các phương thức truy cập này sẽ hành xử khác nhau nếu một biến không được xác định trong phạm vi có liên quan.

Khi bạn đã quyết định coi một tập hợp các biến là một mảng bằng một trong các cơ chế này, bạn có thể thực hiện tất cả các hoạt động tương tự trên nó như trên bất kỳ mảng thông thường nào. Do đó, xem 1.

Chức năng tồn tại chỉ để dự đoán các chức năng này sắp hoạt động như thế nào (ví dụ: "sẽ có một khóa 'foo' trong mảng được trả về bởi get_defined_vars?") Là không cần thiết, vì bạn chỉ cần chạy chức năng và tìm ra không có hiệu ứng xấu.

4a. Biến biến ( $$foo)

Mặc dù không hoàn toàn giống như các hàm biến một tập hợp biến thành một mảng kết hợp, nhưng hầu hết các trường hợp sử dụng "biến biến" ("gán cho một biến có tên dựa trên biến khác này") có thể và nên được thay đổi để sử dụng một mảng kết hợp thay thế .

Một tên biến, về cơ bản, là nhãn được lập trình viên đưa ra một giá trị; nếu bạn xác định nó vào thời gian chạy, nó không thực sự là nhãn mà là chìa khóa trong một số cửa hàng khóa-giá trị. Thực tế hơn, bằng cách không sử dụng một mảng, bạn đang mất khả năng đếm, lặp, v.v; nó cũng có thể trở thành không thể có một biến "bên ngoài" kho lưu trữ khóa-giá trị, vì nó có thể bị ghi đè bởi $$foo.

Sau khi thay đổi để sử dụng một mảng kết hợp, mã sẽ có thể tuân theo giải pháp 1. Truy cập thuộc tính đối tượng gián tiếp (ví dụ $foo->$property_name) có thể được xử lý bằng giải pháp 2.

5. issetrất dễ gõarray_key_exists

Tôi không chắc điều này thực sự có liên quan, nhưng vâng, tên hàm của PHP có thể khá dài dòng và đôi khi không nhất quán. Rõ ràng, các phiên bản tiền sử của PHP đã sử dụng độ dài của tên hàm làm khóa băm, do đó Rasmus cố tình tạo ra các tên hàm như htmlspecialcharsvậy để chúng có số lượng ký tự khác thường ...

Tuy nhiên, ít nhất chúng ta không viết Java, eh? ;)

6. Các biến chưa được khởi tạo có một loại

Các trang hướng dẫn về cơ bản biến bao gồm tuyên bố này:

Các biến chưa được khởi tạo có giá trị mặc định của loại tùy thuộc vào ngữ cảnh mà chúng được sử dụng

Tôi không chắc liệu có một số khái niệm trong Zend Engine về "loại chưa được khởi tạo nhưng đã biết" hay liệu điều này có đang đọc quá nhiều vào tuyên bố hay không.

Điều rõ ràng là nó không tạo ra sự khác biệt thực tế đối với hành vi của họ, vì các hành vi được mô tả trên trang đó đối với các biến chưa được khởi tạo giống hệt với hành vi của một biến có giá trị là null. Để chọn một ví dụ, cả hai $a$btrong mã này sẽ kết thúc dưới dạng số nguyên 42:

unset($a);
$a += 42;

$b = null;
$b += 42;

(Đầu tiên sẽ đưa ra một thông báo về một biến không được khai báo, trong nỗ lực làm cho bạn viết mã tốt hơn, nhưng nó sẽ không tạo ra bất kỳ sự khác biệt nào đối với cách mã thực sự chạy.)

99. Phát hiện nếu một chức năng đã chạy

(Giữ cái này cuối cùng, vì nó dài hơn những cái khác. Có lẽ tôi sẽ chỉnh sửa nó sau ...)

Hãy xem xét các mã sau đây:

$test_value = 'hello';
foreach ( $list_of_things as $thing ) {
    if ( some_test($thing, $test_value) ) {
        $result = some_function($thing);
    }
}
if ( isset($result) ) {
    echo 'The test passed at least once!';
}

Nếu some_functioncó thể trở lại null, có khả năng echosẽ không đạt được mặc dù đã some_testtrả lại true. Ý định của lập trình viên là phát hiện khi nào $resultchưa bao giờ được thiết lập, nhưng PHP không cho phép họ làm như vậy.

Tuy nhiên, có một số vấn đề khác với cách tiếp cận này, sẽ trở nên rõ ràng nếu bạn thêm một vòng lặp bên ngoài:

foreach ( $list_of_tests as $test_value ) {
    // something's missing here...
    foreach ( $list_of_things as $thing ) {
        if ( some_test($thing, $test_value) ) {
            $result = some_function($thing);
        }
    }
    if ( isset($result) ) {
        echo 'The test passed at least once!';
    }
}

Bởi vì $resultkhông bao giờ được khởi tạo một cách rõ ràng, nó sẽ đảm nhận một giá trị khi lần thử nghiệm đầu tiên trôi qua, khiến cho không thể biết liệu các thử nghiệm tiếp theo có vượt qua hay không. Đây thực sự là một lỗi cực kỳ phổ biến khi các biến không được khởi tạo đúng cách.

Để khắc phục điều này, chúng tôi cần phải làm một cái gì đó trên dòng mà tôi đã nhận xét rằng thiếu một cái gì đó. Giải pháp rõ ràng nhất là đặt thành $result"giá trị đầu cuối" some_functionkhông bao giờ có thể quay lại; nếu điều này là null, phần còn lại của mã sẽ hoạt động tốt. Nếu không có ứng cử viên tự nhiên cho giá trị đầu cuối vì some_functioncó loại trả về cực kỳ khó đoán (có thể là dấu hiệu xấu trong chính nó), thì $foundcó thể sử dụng giá trị boolean bổ sung, ví dụ:

Suy nghĩ thử nghiệm một: very_nullhằng số

Về mặt lý thuyết, PHP có thể cung cấp một hằng số đặc biệt - cũng như null- để sử dụng làm giá trị đầu cuối ở đây; có lẽ, việc trả lại điều này từ một hàm là bất hợp pháp, hoặc nó sẽ bị ép buộc null, và điều tương tự có thể sẽ được áp dụng để chuyển nó thành một đối số hàm. Điều đó sẽ làm cho trường hợp rất cụ thể này trở nên đơn giản hơn một chút, nhưng ngay khi bạn quyết định tính lại mã - ví dụ, để đặt vòng lặp bên trong vào một hàm riêng biệt - nó sẽ trở nên vô dụng. Nếu hằng số có thể được truyền giữa các hàm, bạn không thể đảm bảo rằng nó some_functionsẽ không trả về nó, vì vậy nó sẽ không còn hữu ích như một giá trị đầu cuối phổ quát.

Đối số để phát hiện các biến chưa được khởi tạo trong trường hợp này rút ra đối số cho hằng số đặc biệt đó: nếu bạn thay thế nhận xét unset($result)và xử lý khác với đó $result = null, bạn đang đưa ra một "giá trị" cho $resultđiều đó không thể được thông qua và chỉ có thể được chuyển được phát hiện bởi các chức năng tích hợp cụ thể.

Thử nghiệm suy nghĩ hai: bộ đếm chuyển nhượng

Một cách nghĩ khác về những gì cuối cùng ifđang hỏi là "có gì được giao $resultkhông?" Thay vì coi nó là một giá trị đặc biệt $result, bạn có thể nghĩ đây là "siêu dữ liệu" về biến, giống như "biến đổi" của Perl. Vì vậy, thay vì issetbạn có thể gọi nó has_been_assigned_to, và hơn là unset, reset_assignment_state.

Nhưng nếu vậy, tại sao dừng lại ở một boolean? Điều gì sẽ xảy ra nếu bạn muốn biết thử nghiệm đã vượt qua bao nhiêu lần ; bạn chỉ có thể mở rộng siêu dữ liệu của mình thành một số nguyên và có get_assignment_countreset_assignment_count...

Rõ ràng, việc thêm một tính năng như vậy sẽ có sự đánh đổi về độ phức tạp và hiệu suất của ngôn ngữ, vì vậy nó sẽ cần được cân nhắc cẩn thận với tính hữu dụng dự kiến ​​của nó. Như với một very_nullhằng số, nó sẽ chỉ hữu ích trong các trường hợp rất hẹp và có khả năng chống lại sự bao thanh toán tương tự.

Câu hỏi hy vọng rõ ràng là tại sao công cụ thời gian chạy PHP nên giả định trước rằng bạn muốn theo dõi những điều đó, thay vì để bạn làm điều đó một cách rõ ràng, sử dụng mã bình thường.


Về các lớp và thuộc tính, đáng buồn là property_exists () không hoạt động khi thuộc tính là mảng, ví dụ: Class {public $ property = Array ()}. Ném một lỗi.
Andrew

1
@Andrew Có vẻ hoạt động tốt với tôi: 3v4l.org/TnAY5 Bạn có muốn cung cấp một ví dụ hoàn chỉnh không?
IMSoP

Vâng, nó có vẻ hoạt động tốt, có gì đó không ổn với thiết lập của tôi. Xin lỗi vì báo động sai :)
Andrew

20

Đôi khi tôi cảm thấy hơi mất công khi cố gắng tìm ra thao tác so sánh nào sẽ được sử dụng trong một tình huống nhất định. isset()chỉ áp dụng cho các giá trị null chưa được khởi tạo hoặc rõ ràng. Truyền / gán null là một cách tuyệt vời để đảm bảo so sánh logic hoạt động như mong đợi.

Tuy nhiên, có một chút khó khăn để suy nghĩ vì vậy đây là một ma trận đơn giản so sánh các giá trị khác nhau sẽ được đánh giá bằng các hoạt động khác nhau như thế nào:

|           | ===null | is_null | isset | empty | if/else | ternary | count>0 |
| -----     | -----   | -----   | ----- | ----- | -----   | -----   | -----   |
| $a;       | true    | true    |       | true  |         |         |         |
| null      | true    | true    |       | true  |         |         |         |
| []        |         |         | true  | true  |         |         |         |
| 0         |         |         | true  | true  |         |         | true    |
| ""        |         |         | true  | true  |         |         | true    |
| 1         |         |         | true  |       | true    | true    | true    |
| -1        |         |         | true  |       | true    | true    | true    |
| " "       |         |         | true  |       | true    | true    | true    |
| "str"     |         |         | true  |       | true    | true    | true    |
| [0,1]     |         |         | true  |       | true    | true    | true    |
| new Class |         |         | true  |       | true    | true    | true    |

Để phù hợp với bảng tôi đã nén các nhãn một chút:

  • $a; đề cập đến một biến được khai báo nhưng không được gán
  • mọi thứ khác trong cột đầu tiên đề cập đến một giá trị được gán, như:
    • $a = null;
    • $a = [];
    • $a = 0;
    • Giáo dục
  • các cột đề cập đến các hoạt động so sánh, như:
    • $a === null
    • isset($a)
    • empty($a)
    • $a ? true : false
    • Giáo dục

Tất cả các kết quả là boolean, trueđược in và falseđược bỏ qua.

Bạn có thể tự chạy các bài kiểm tra, kiểm tra ý chính này:
https://gist.github.com/mfdj/8165967


Có thể nằm ngoài phạm vi của câu hỏi này, nhưng bạn có thể muốn thêm "0"vào bảng, vì tính đầy đủ và rõ ràng của emptythao tác
Rik Schaaf

17

Bạn có thể sử dụng cấu trúc ngôn ngữ nhỏ gọn để kiểm tra sự tồn tại của biến null. Các biến không tồn tại sẽ không xuất hiện trong kết quả, trong khi các giá trị null sẽ hiển thị.

$x = null;
$y = 'y';

$r = compact('x', 'y', 'z');
print_r($r);

// Output:
// Array ( 
//  [x] => 
//  [y] => y 
// ) 

Trong trường hợp ví dụ của bạn:

if (compact('v')) {
   // True if $v exists, even when null. 
   // False on var $v; without assignment and when $v does not exist.
}

Tất nhiên đối với các biến trong phạm vi toàn cầu, bạn cũng có thể sử dụng mảng_key_exists ().

Cá nhân Btw tôi sẽ tránh các tình huống như bệnh dịch hạch nơi có sự khác biệt về ngữ nghĩa giữa một biến không tồn tại và biến có giá trị null. PHP và hầu hết các ngôn ngữ khác không nghĩ là có.


3
PHP thì không, nhưng tôi sẽ không nói hầu hết các ngôn ngữ khác. Hầu hết mọi ngôn ngữ khai báo các biến sẽ đưa ra lỗi nếu một biến chưa được khai báo, nhưng bạn có thể đặt chúng thành NULL. Về mặt ngữ nghĩa, NULLcó nghĩa là "không có tài nguyên", nhưng không xác định biến là lỗi lập trình.
M Miller

1
@MMiller Chắc chắn, nhưng viết mã theo một đường dẫn trong trường hợp "không có tài nguyên" và một đường dẫn khác trong trường hợp "lỗi lập trình viên" là khá vô lý. Nếu bạn muốn phát hiện các biến không được khai báo trong quá trình gỡ lỗi, hãy sử dụng công cụ phân tích tĩnh, giống như bạn sẽ tìm thấy các lỗi tiềm ẩn trong bất kỳ ngôn ngữ nào.
IMSoP

@MMiller, tuyệt, bạn thậm chí đã nghĩ về điều này như thế nào.
Pacerier

1
@MMiller Nhưng nó không hoạt động như một phản bác, bởi vì câu lệnh trong câu trả lời rõ ràng là về "một biến không tồn tại" và ví dụ phản biện của bạn là về một thuộc tính đối tượng / khóa băm không tồn tại . Sự khác biệt giữa các trường hợp này không chỉ là ngẫu nhiên.
IMSoP

1
@MMiller - thực sự đó là một ví dụ tốt hơn. Tuy nhiên, sau hơn 20 năm lập trình bằng các ngôn ngữ nghiêm ngặt, các tình huống mà tôi cần một sự khác biệt giữa undefinednullrất hiếm khi tôi không bỏ lỡ nó. IMHO, công dụng chính của undefined"lỗi lập trình viên trong một ngôn ngữ không nghiêm ngặt". Trong một ngôn ngữ nghiêm ngặt, nếu tôi cần một trạng thái riêng biệt client did not state a value, thì tôi khai báo một giá trị phù hợp với tình huống và kiểm tra nó. Trường hợp xấu nhất, phải thêm một biến cờ riêng. Nhưng làm điều đó hiếm khi tốt hơn là phải LUÔN đối phó với HAI trạng thái không giá trị khác nhau !!
ToolmakerSteve

15

Giải thích về NULL, suy nghĩ logic

Tôi đoán câu trả lời rõ ràng cho tất cả những điều này là ... Đừng khởi tạo các biến của bạn dưới dạng NULL, kích hoạt chúng như một cái gì đó có liên quan đến những gì chúng dự định trở thành.

Điều trị NULL đúng cách

NULL nên được coi là "giá trị không tồn tại", đó là ý nghĩa của NULL. Biến không thể được phân loại là tồn tại với PHP bởi vì nó đã không được cho biết loại thực thể mà nó đang cố gắng trở thành. Nó có thể không tồn tại, vì vậy PHP chỉ nói "Tốt thôi, không phải vì dù sao cũng không có điểm nào và NULL là cách tôi nói điều này".

Một cuộc tranh cãi

Bây giờ hãy tranh luận. "Nhưng NULL giống như nói 0 hoặc FALSE hoặc ''.

Sai, 0-FALSE- '' tất cả vẫn được phân loại là giá trị trống, nhưng chúng được chỉ định là một số loại giá trị hoặc câu trả lời được xác định trước cho một câu hỏi. FALSE là câu trả lời cho có hoặc không, '' là câu trả lời cho tiêu đề mà ai đó đã gửi và 0 là câu trả lời cho số lượng hoặc thời gian, v.v. Chúng được đặt là một loại câu trả lời / kết quả khiến chúng có giá trị như được đặt.

NULL chỉ là không có câu trả lời cho đến nay, nó không cho chúng tôi biết có hay không và nó không cho chúng tôi biết thời gian và nó không cho chúng tôi biết một chuỗi trống đã được gửi. Đó là logic cơ bản để hiểu NULL.

Tóm lược

Đây không phải là về việc tạo ra các chức năng lập dị để giải quyết vấn đề, nó chỉ thay đổi cách não bạn nhìn vào NULL. Nếu là NULL, giả sử nó không được đặt là bất cứ điều gì. Nếu bạn đang xác định trước các biến thì hãy xác định trước chúng là 0, FALSE hoặc "" tùy thuộc vào loại sử dụng mà bạn dự định sử dụng chúng.

Hãy trích dẫn điều này. Nó nằm ngoài đỉnh đầu logic của tôi :)


5
Câu trả lời chính xác. Vì vậy, nhiều lần tôi thấy mọi người ca ngợi về cách họ ghét tính năng này hoặc tính năng của ngôn ngữ. Nhưng dường như họ đang cho rằng "nếu nó không làm theo cách của tôi thì nó đã bị hỏng". Vâng, có những quyết định thiết kế tồi. Nhưng cũng có những nhà phát triển rất gần gũi!
curtisdf

23
Có sự khác biệt lớn giữa biến unset và biến === null. Một cái không tồn tại, cái kia có giá trị null. Đối số cho rằng null có nghĩa là không có giá trị đơn giản là không đúng. Null LÀ GIÁ TRỊ loại null. Đó là giá trị hoàn toàn hợp lệ và không có lý do gì để php coi nó là giá trị không tồn tại, điều đáng buồn là nó làm. Sẽ ổn thôi, nếu các biến không tồn tại là null và mọi biến hiện tại không phải là null và việc gán null vào biến sẽ bỏ đặt nó. Nhưng có NHIỀU tình huống, trong đó các hàm trả về null là giá trị thực. Sau đó, chúng tôi thất vọng, bởi vì không có cách nào để kiểm tra nó.
enrey

2
Tôi biết chúng ta "không nên" kiểm tra sự tồn tại của biến trong php, chết tiệt, thậm chí không có cách nào thực sự để kiểm tra nó. Tôi sẽ không viết mã phụ thuộc vào nó, bởi vì nó không thể thực hiện được bằng php. Đó là một hạn chế của php. Rõ ràng có một sự khác biệt giữa biến không được đặt và biến null, nhưng php không cung cấp cách nào để phân biệt chúng. Tuy nhiên, rất nhiều chức năng meta phụ thuộc vào nội bộ: đọc var không tồn tại tạo ra thông báo, isset($a['x'])sẽ cho bạn biết nếu xlà null, nhưng nó sẽ hiển thị trong count($a).. compactsẽ hoạt động trên tất cả các biến đã đặt, bao gồm nulls, v.v.
enrey

3
Câu trả lời này còn thiếu sót theo một cách chính: trong lập trình OO, null là lựa chọn hợp lý có nghĩa là "không có đối tượng". Ví dụ, trong các trường hợp ngoại lệ khi một hàm có thể trả về một đối tượng hoặc không có đối tượng, null là lựa chọn rõ ràng. Về mặt kỹ thuật trong PHP, sai hoặc bất kỳ giá trị nào khác được coi là sai trong ngữ cảnh boolean có thể được sử dụng, nhưng sau đó bạn sẽ mất một số độ tinh khiết về ngữ nghĩa. Do đó, null là một giá trị hoàn toàn hợp lý để khởi tạo một biến để giữ một đối tượng cuối cùng, bởi vì nó liên quan đến những gì nó dự định trở thành.
chazomaticus

3
Miễn là PHP ném lỗi cho các biến không xác định, nhưng không phải là null, thì có một sự khác biệt. Nếu null và không xác định thực sự là cùng một khái niệm, thì PHP sẽ giả sử các biến không xác định / không khai báo mặc định thành null và không bao giờ đưa ra lỗi, nhưng không ai muốn điều đó bởi vì đó là cơn ác mộng phát triển. Null và không xác định có thể không thực sự khác nhau trong bối cảnh ngữ nghĩa giá trị, nhưng chúng rất khác nhau khi viết mã rõ ràng và có thể sửa lỗi.
Chris Middleton

9

Các thuộc tính đối tượng có thể được kiểm tra sự tồn tại của property_exists

Ví dụ từ một bài kiểm tra đơn vị:

function testPropertiesExist()
{
    $sl =& $this->system_log;
    $props = array('log_id',
                   'type',
                   'message',
                   'username',
                   'ip_address',
                   'date_added');

    foreach($props as $prop) {
        $this->assertTrue(property_exists($sl, $prop),
                           "Property <{$prop}> exists");
    }
}

4

Là một bổ sung cho cuộc thảo luận của greatbigmassive về ý nghĩa của NULL , hãy xem xét "sự tồn tại của một biến" thực sự có nghĩa là gì.

Trong nhiều ngôn ngữ, bạn phải khai báo rõ ràng mọi biến trước khi sử dụng nó ; điều này có thể xác định loại của nó, nhưng quan trọng hơn là nó tuyên bố phạm vi của nó . Một biến "tồn tại" ở mọi nơi trong phạm vi của nó và không ở đâu ngoài nó - có thể là toàn bộ một hàm hoặc một "khối" duy nhất.

Trong phạm vi của nó, một biến gán một số ý nghĩa cho nhãn mà bạn, lập trình viên, đã chọn. Ngoài phạm vi của nó, nhãn đó là vô nghĩa (cho dù bạn sử dụng cùng một nhãn trong một phạm vi khác về cơ bản là không liên quan).

Trong PHP, các biến không cần phải khai báo - chúng xuất hiện ngay khi bạn cần chúng. Khi bạn viết vào một biến lần đầu tiên, PHP sẽ cấp phát một mục trong bộ nhớ cho biến đó. Nếu bạn đọc từ một biến hiện không có mục, PHP sẽ coi biến đó có giá trị NULL.

Tuy nhiên, các trình phát hiện chất lượng mã tự động thường sẽ cảnh báo bạn nếu bạn sử dụng một biến mà không "khởi tạo" nó trước. Thứ nhất, điều này giúp phát hiện lỗi chính tả, chẳng hạn như gán cho$thingId nhưng đọc từ $thing_id; nhưng thứ hai, nó buộc bạn phải xem xét phạm vi mà biến đó có ý nghĩa, giống như một tuyên bố.

Bất kỳ mã nào quan tâm đến việc một biến "tồn tại" có phải là một phần của phạm vi của biến đó không đó hay không - có được khởi tạo hay không, bạn với tư cách là một lập trình viên đã đưa ra ý nghĩa nhãn đó tại điểm đó của mã. Vì bạn đang sử dụng nó, theo một nghĩa nào đó nó "tồn tại" và nếu nó tồn tại, nó phải có một giá trị ngầm định; trong PHP, giá trị ngầm định đó là null.

Do cách thức hoạt động của PHP, có thể viết mã xử lý không gian tên của các biến tồn tại không phải là một phạm vi nhãn mà bạn đã đưa ra ý nghĩa, mà như một loại lưu trữ khóa-giá trị. Ví dụ, bạn có thể chạy mã như thế này:$var = $_GET['var_name']; $$var = $_GET['var_value']; . Chỉ vì bạn có thể, không có nghĩa đó là một ý tưởng tốt.

Hóa ra, PHP có cách biểu diễn các cửa hàng khóa-giá trị tốt hơn nhiều, được gọi là mảng kết hợp. Và mặc dù các giá trị của một mảng có thể được coi như các biến, bạn cũng có thể thực hiện các thao tác trên toàn bộ mảng. Nếu bạn có một mảng kết hợp, bạn có thể kiểm tra nếu nó chứa khóa bằng cách sử dụngarray_key_exists() .

Bạn cũng có thể sử dụng các đối tượng theo cách tương tự, thiết lập động các thuộc tính, trong trường hợp đó bạn có thể sử dụng property_exists()theo cùng một cách chính xác. Tất nhiên, nếu bạn định nghĩa một lớp, bạn có thể khai báo mà tính nó đã - bạn thậm chí có thể lựa chọn giữa public, privateprotectedphạm vi.

Mặc dù có một sự khác biệt về kỹ thuật giữa một biến (trái ngược với khóa mảng hoặc thuộc tính đối tượng) chưa được khởi tạo (hoặc đã được xác định rõ ràng unset()) và một giá trị là null, bất kỳ mã nào coi sự khác biệt đó đều có ý nghĩa đang sử dụng các biến theo cách mà chúng không được sử dụng.


1
Điểm rất tốt, mặc dù không chính xác một câu trả lời cho câu hỏi.
chazomaticus

1
Đối với câu hỏi rõ ràng "Làm thế nào chúng ta phải kiểm tra sự tồn tại của một biến trong PHP một cách đáng tin cậy?" câu trả lời của tôi là "bạn không phải, và đây là lý do tại sao". Cả câu trả lời này và greatbigmassive cũng trả lời câu hỏi ngầm "tại sao lại isset()hành xử theo cách đó?".
IMSoP

"Nếu bạn đọc từ một biến hiện không có mục, PHP sẽ coi biến đó có giá trị NULL." Điều này là sai. Một biến không xác định đơn giản là không xác định. Nó có thể trả về null khi bạn cố gắng truy cập nó, nhưng điều đó không liên quan.
Hugo Zink

@HugoZink Không liên quan đến cái gì? Bất kỳ kiểm tra nào bạn thực hiện về giá trị của một biến không xác định sẽ cho bạn biết rằng giá trị đó là null. Cho dù giá trị đó tồn tại trước khi bạn nhìn vào nó là một câu hỏi cho các nhà triết học, nhưng theo như bất kỳ hành vi quan sát được liên quan đến giá trị là nhất quán null.
IMSoP

3

issetkiểm tra xem biến có được đặt không và nếu có thì giá trị của nó không phải là NULL. Phần sau là (theo ý kiến ​​của tôi) không nằm trong phạm vi của chức năng này. Không có cách giải quyết hợp lý để xác định xem một biến là NULL vì nó không được đặt hoặc vì nó được đặt rõ ràng thành NULL .

Đây là một giải pháp khả thi:

$e1 = error_get_last();
$isNULL = is_null(@$x);
$e2 = error_get_last();
$isNOTSET = $e1 != $e2;
echo sprintf("isNOTSET: %d, isNULL: %d", $isNOTSET, $isNULL);

// Sample output:
// when $x is not set: isNOTSET: 1, isNULL: 1
// when $x = NULL:     isNOTSET: 0, isNULL: 1
// when $x = false:    isNOTSET: 0, isNULL: 0

Cách giải quyết khác là thăm dò đầu ra của get_defined_vars():

$vars = get_defined_vars();
$isNOTSET = !array_key_exists("x", $vars);
$isNULL = $isNOTSET ? true : is_null($x);
echo sprintf("isNOTSET: %d, isNULL: %d", $isNOTSET, $isNULL);

// Sample output:
// when $x is not set: isNOTSET: 1, isNULL: 1
// when $x = NULL:     isNOTSET: 0, isNULL: 1
// when $x = false:    isNOTSET: 0, isNULL: 0

2

Tôi không đồng ý với lý luận của bạn về NULL và nói rằng bạn cần thay đổi suy nghĩ về NULL thật kỳ lạ.

Tôi nghĩ rằngetet () không được thiết kế chính xác, isset () sẽ cho bạn biết nếu biến đã được đặt và nó không liên quan đến giá trị thực của biến.

Điều gì sẽ xảy ra nếu bạn đang kiểm tra các giá trị được trả về từ cơ sở dữ liệu và một trong các cột có giá trị NULL, bạn vẫn muốn biết liệu nó có tồn tại ngay cả khi giá trị đó là NULL ... không tin tưởng ngay lập tức ở đây.

tương tự như vậy

$a = array ('test' => 1, 'hello' => NULL);

var_dump(isset($a['test']));   // TRUE
var_dump(isset($a['foo']));    // FALSE
var_dump(isset($a['hello']));  // FALSE

Ngay lập tức () nên được thiết kế để hoạt động như thế này:

if(isset($var) && $var===NULL){....

bằng cách này, chúng tôi để cho lập trình viên kiểm tra các loại và không để nó lên đến ngay lập tức () để cho rằng nó không có ở đó vì giá trị là NULL - thiết kế ngu ngốc của nó


Ví dụ của bạn không kiểm tra sự tồn tại của một biến, mà là một khóa mảng. Một giải pháp cho điều đó tồn tại, dưới hình thức array_key_exists. Bạn không bao giờ nên ở trong một tình huống mà bạn không biết trong thời gian chạy nếu một biến thực sự tồn tại.
IMSoP

@chazomaticus Chà, bạn không bao giờ nên ở trong tình huống mà register_globals được bật, vì vậy tôi đứng trước tuyên bố đó.
IMSoP

Ồ, tôi đồng ý. Tuy nhiên, không phải ai cũng có thể kiểm soát nơi mã của họ được triển khai. Thật hữu ích khi có thông tin cho mọi tình huống, cho dù đó là cách mọi thứ "nên" hay không.
chazomaticus

@chazomaticus Nếu vấn đề của bạn là register_globals, thì câu trả lời của bạn không phải là thay đổi isset(). Hướng dẫn PHP đề cập "thực sự nói chung là một thực hành lập trình tốt để khởi tạo các biến trước", nó giải quyết register_globalstại thời điểm thiết kế thay vì thời gian chạy. Ngoài ra còn có một mục FAQ cung cấp một unregister_globals()chức năng để đối phó với nó trong thời gian chạy.
IMSoP

2

Tôi sẽ thêm hai xu nhanh chóng vào đây. Một lý do khiến vấn đề này trở nên khó hiểu là vì kịch bản này dường như trả về cùng một kết quả với báo cáo lỗi không đầy đủ:

$a = null;
var_dump($a); // NULL
var_dump($b); // NULL

Bạn có thể cho rằng từ kết quả này, sự khác biệt giữa $a = nullvà không xác định $bgì cả là không có gì.

Báo cáo lỗi crank lên:

NULL

Notice: Undefined variable: b in xxx on line n
NULL

Lưu ý: nó đã ném một lỗi biến không xác định, nhưng giá trị đầu ra var_dumpvẫn là NULL.

PHP rõ ràng có một khả năng nội bộ để phân biệt giữa một biến null và một biến không xác định. Dường như với tôi rằng nên có một chức năng tích hợp để kiểm tra điều này.

Tôi nghĩ rằng câu trả lời được chấp nhận là tốt cho hầu hết các phần, nhưng nếu tôi sẽ thực hiện nó, tôi sẽ viết một trình bao bọc cho nó. Như đã đề cập trước đây trong câu trả lời này , tôi phải đồng ý rằng tôi thực sự đã gặp phải một tình huống mà đây là một vấn đề. Tôi dường như luôn luôn kết thúc trong một kịch bản trong đó các biến của tôi được đặt và được xác định hoặc chúng không (không xác định, không đặt, null, để trống, v.v.). Không nói rằng một tình huống như thế này sẽ không xảy ra trong tương lai, nhưng vì nó dường như là một vấn đề khá độc đáo, tôi không ngạc nhiên khi các nhà phát triển PHP không bận tâm đến vấn đề này.


Cảnh báo về các biến không xác định là một gợi ý cho lập trình viên rằng họ đã làm sai điều gì đó trong mã. Gỡ lỗi bên ngoài (trong đó có các công cụ bên ngoài ngôn ngữ), không bao giờ cần một chương trình để phát hiện trạng thái như vậy, bởi vì lập trình viên phải luôn biết những biến nào họ đang khai báo.
IMSoP

1

Nếu tôi chạy như sau:

echo '<?php echo $foo; ?>' | php

Tôi gặp lỗi:

PHP Notice:  Undefined variable: foo in /home/altern8/- on line 1

Nếu tôi chạy như sau:

echo '<?php if ( isset($foo) ) { echo $foo; } ?>' | php

Tôi không nhận được lỗi.

Nếu tôi có một biến nên được đặt, tôi thường làm một cái gì đó như sau.

$foo = isset($foo) ? $foo : null;

hoặc là

if ( ! isset($foo) ) $foo = null;

Bằng cách đó, sau này trong tập lệnh, tôi có thể sử dụng $ foo một cách an toàn và biết rằng nó "được đặt" và nó mặc định là null. Sau này tôi có thể if ( is_null($foo) ) { /* ... */ }nếu tôi cần và biết chắc chắn rằng biến đó tồn tại, ngay cả khi nó là null.

Tài liệu đầy đủ củaetet đọc nhiều hơn một chút so với những gì ban đầu được dán. Có, nó trả về false cho một biến đã được đặt trước đó nhưng bây giờ là null, nhưng nó cũng trả về false nếu một biến chưa được đặt (bao giờ) và cho bất kỳ biến nào được đánh dấu là không được đặt. Nó cũng lưu ý rằng byte NULL ("\ 0") không được coi là null và sẽ trả về true.

Xác định xem một biến được đặt.

Nếu một biến đã được bỏ đặt với unset (), nó sẽ không còn được đặt. isset () sẽ trả về SAI nếu kiểm tra một biến đã được đặt thành NULL. Cũng lưu ý rằng một byte NULL ("\ 0") không tương đương với hằng số NULL PHP.


Ông đã nhận được các tài liệu ra khỏi liên kết đó. Đọc câu đầu tiên, đoạn thứ hai của phần mô tả về liên kết bạn cung cấp Đó chính xác là những gì anh ấy trích dẫn ở trên.
Zoredache

Đây không phải là một thực tiễn tồi cho các tập lệnh đơn giản, nhưng trong các dự án phức tạp (ví dụ OO lớn), nó trở nên không khả thi. Ngoài ra, như tôi đã nói ở trên, is_null () trả về TRUE cho các biến không được đặt, vì vậy thực sự không có lý do gì để làm những gì bạn đang nói ngoại trừ để tránh cảnh báo PHP.
chazomaticus

1
Đối với các dự án "OO lớn" được thiết kế tốt, tại sao điều này lại là một vấn đề? Tại sao bạn lại có $ foo trong phần thân phương thức có thể chưa được đặt trước lần sử dụng đầu tiên?
Beau Simensen

1

Hãy thử sử dụng

unset($v)

Có vẻ như lần duy nhất một biến không được đặt là khi nó không được đặt riêng ($ v). Có vẻ như ý nghĩa của bạn về 'sự tồn tại' khác với định nghĩa của PHP. NULL chắc chắn là tồn tại, nó là NULL.


Tôi không chắc ý của bạn là gì. Nếu bạn có một mảng, với một phần tử 'a', bạn không phải bỏ đặt phần tử () 'b' cho phần tử 'b' không tồn tại trong PHP, nó chỉ không tồn tại. Điều tương tự với các biến toàn cục, ví dụ như các biến toàn cục, mà bạn có thể nghĩ là các phần tử của mảng $ GLOBALS.
chazomaticus

1
Nhưng tôi đồng ý rằng một biến có giá trị NULL thực tế tồn tại.
chazomaticus

0

Tôi phải nói rằng trong tất cả các năm lập trình PHP, tôi chưa bao giờ gặp phải vấn đề gì isset()khi trả về false trên biến null. OTOH, tôi đã gặp phải vấn đề với isset()thất bại trong mục nhập mảng null - nhưng array_key_exists()hoạt động chính xác trong trường hợp đó.

Đối với một số so sánh, Icon xác định rõ ràng một biến không được sử dụng là trả về &nullđể bạn sử dụng kiểm tra is-null trong Biểu tượng để kiểm tra biến không đặt. Điều này không làm cho mọi thứ dễ dàng hơn. Mặt khác, Visual BASIC có nhiều trạng thái cho một biến không có giá trị (Null, Empty, nothing, ...) và bạn thường phải kiểm tra nhiều hơn một trong số chúng. Điều này được biết đến là một nguồn lỗi.


0

Theo Hướng dẫn sử dụng PHP cho hàm rỗng (), "Xác định xem một biến có được coi là trống hay không. Một biến được coi là trống NẾU KHÔNG KHÔNG EXIST hoặc nếu giá trị của nó bằng FALSE. Trống () không tạo cảnh báo nếu biến không tồn tại. " (Tôi nhấn mạnh.) Điều đó có nghĩa là hàm rỗng () phải đủ điều kiện là "cách tốt nhất để kiểm tra sự tồn tại của một biến trong PHP", theo câu hỏi tiêu đề.

Tuy nhiên, điều này không đủ tốt, bởi vì hàm rỗng () có thể bị đánh lừa bởi một biến tồn tại và được đặt thành NULL.

Tôi đang ngắt câu trả lời trước đó của tôi để trình bày một cái gì đó tốt hơn, bởi vì nó ít cồng kềnh hơn câu trả lời ban đầu của tôi (theo sau sự gián đoạn này, để so sánh).

  function undef($dnc) //do not care what we receive
  { $inf=ob_get_contents();             //get the content of the buffer
    ob_end_clean();                     //stop buffering outputs, and empty the buffer
    if($inf>"")                         //if test associated with the call to this function had an output
    { if(false!==strpos($inf, "Undef"); //if the word "Undefined" was part of the output
        return true;                    //tested variable is undefined
    }
    return false;                       //tested variable is not undefined
  }

Hai dòng mã đơn giản có thể sử dụng hàm trên để tiết lộ nếu một biến không được xác định:

  ob_start();                           //pass all output messages (including errors) to a buffer
  if(undef($testvar===null))            //in this case the variable being tested is $testvar

Bạn có thể theo dõi hai dòng đó với bất cứ điều gì phù hợp, chẳng hạn như ví dụ này:

    echo("variable is undefined");
  else
    echo("variable exists, holding some value");

Tôi muốn đặt lệnh gọi tới ob_start () và ($ testvar === null) bên trong hàm và chỉ cần truyền biến cho hàm, nhưng nó không hoạt động. Ngay cả khi bạn cố gắng sử dụng "truyền bằng tham chiếu" của biến cho hàm, biến BECOMES được xác định và sau đó hàm không bao giờ có thể phát hiện ra rằng trước đó nó không được xác định. Những gì được trình bày ở đây là một sự thỏa hiệp giữa những gì tôi muốn làm và những gì thực sự hoạt động.

Phần trước ngụ ý rằng có một cách khác để luôn tránh chạy vào thông báo lỗi "Biến không xác định". (Giả định ở đây là, ngăn chặn một thông báo như vậy là lý do tại sao bạn muốn kiểm tra xem liệu một biến không được xác định.)

   function inst(&$v) { return; }  //receive any variable passed by reference; instantiates the undefined

Chỉ cần gọi hàm đó trước khi làm điều gì đó với $ testvar của bạn:

   inst($testvar);                //The function doesn't affect any value of any already-existing variable

Tất nhiên, giá trị của biến mới được đặt thành null

(Ngắt kết thúc)

Vì vậy, sau một số nghiên cứu và thử nghiệm, đây là một cái gì đó được đảm bảo để làm việc:

 function myHndlr($en, $es, $ef, $el)
 { global $er;
   $er = (substr($es, 0, 18) == "Undefined variable");
   return;
 }

 $er = false;
 if(empty($testvar))
 { set_error_handler("myHndlr");
   ($testvar === null);
   restore_error_handler();
 }
 if($er)  // will be 1 (true) if the tested variable was not defined.
 { ; //do whatever you think is appropriate to the undefined variable
 }

Giải thích: Một biến $ er được khởi tạo thành giá trị mặc định là "không có lỗi". Một "hàm xử lý" được định nghĩa. Nếu $ testvar (biến mà chúng ta muốn biết có xác định được hay không) vượt qua kiểm tra hàm rỗng () sơ bộ, thì chúng ta sẽ thực hiện kiểm tra kỹ lưỡng hơn. Chúng tôi gọi hàm set_error_handler () để sử dụng hàm xử lý được xác định trước đó. Sau đó, chúng tôi thực hiện một so sánh nhận dạng đơn giản liên quan đến $ testvar, MÀ NẾU KHÔNG HIỂU SILL TRIGGER AN ERROR. Hàm xử lý nắm bắt lỗi và kiểm tra cụ thể để xem liệu lý do lỗi có phải là thực tế là biến không được xác định. Kết quả được đặt trong biến thông tin lỗi $ er, mà sau này chúng ta có thể kiểm tra để làm bất cứ điều gì chúng ta muốn do biết chắc chắn liệu $ testvar có được xác định hay không. Bởi vì chúng tôi chỉ cần chức năng xử lý cho mục đích giới hạn này, chúng tôi khôi phục chức năng xử lý lỗi ban đầu. Hàm "myHndlr" chỉ cần được khai báo một lần; mã khác có thể được sao chép vào bất kỳ nơi nào phù hợp, với $ testvar hoặc bất kỳ biến nào khác mà chúng tôi muốn kiểm tra theo cách này.


1
Nếu mục đích là để tránh cảnh báo rằng các biến của bạn chưa được khai báo, thì giải pháp là sửa mã của bạn để khai báo chúng đúng. instChức năng của bạn về cơ bản giống như @toán tử khắc phục lỗi: "Tôi biết tôi đang làm gì đó sai ở đây, nhưng tôi chỉ muốn thông báo đó biến mất, mà không thực sự thay đổi hoạt động của mã theo bất kỳ cách nào".
IMSoP

Mặt khác, các phương pháp phát hiện rất tài tình, nhưng tôi vẫn tin chắc rằng bạn không bao giờ nên sử dụng chúng ngoài việc lặp lại những thông điệp cảnh báo mà họ đang bắt. (Bạn có thể nên làm rõ rằng phiên bản bộ đệm đầu ra của bạn yêu cầu lỗi thông báo được đặt ở mức cao và display_errors được bật.)
IMSoP

0

Tôi nghĩ rằng giải pháp đầy đủ duy nhất là báo cáo các thông báo với

error_reporting(E_ALL); // Enables E_NOTICE

Nhưng bạn sẽ phải sửa tất cả các thông báo được tạo bởi các biến không xác định, hằng, khóa mảng, thuộc tính lớp trong số các thông báo khác. Một khi bạn đã làm xong, bạn sẽ không phải lo lắng về sự khác biệt giữa các biến null và không được khai báo, và sự biến mất mơ hồ.

Kích hoạt báo cáo thông báo có thể không phải là một lựa chọn tốt trong mọi tình huống, nhưng có những lý do chính đáng để kích hoạt nó:

Tại sao tôi nên sửa lỗi E_NOTICE?

Trong trường hợp của tôi là hơn một năm làm việc trong một proyect mà không có nó, nhưng được sử dụng để cẩn thận về việc khai báo các biến, vì vậy nó đã nhanh chóng chuyển đổi.


0

Cách duy nhất để biết nếu một biến được xác định trong phạm vi hiện tại ( $GLOBALSkhông đáng tin cậy) là array_key_exists( 'var_name', get_defined_vars() ).


1
Tôi nghĩ đó là những gì nhiều người khác đã nói trước đây, hoặc tôi sai?
Stephan Vierkant

-1

Tôi thích sử dụng không rỗng như phương pháp tốt nhất để kiểm tra sự tồn tại của một biến mà a) tồn tại và b) không phải là null.

if (!empty($variable)) do_something();

2
empty()không kiểm tra xem biến đó có phải là null hay không, nó sẽ kiểm tra xem đó có phải là false-y hay không, ví dụ không phải là một trong ""(một chuỗi rỗng), 0(0 dưới dạng số nguyên), 0.0(0 dưới dạng float), "0"(0 dưới dạng chuỗi) ,, NULL. FALSE, array()(một mảng trống) và $var;(một biến được khai báo, nhưng không có giá trị). Giả sử bạn có một trường vô tuyến bắt buộc ở dạng có hai đầu vào với các giá trị 01. Nếu bạn sử dụng empty()để xác thực và người dùng chọn 0một, bạn sẽ vô tình báo lỗi "trường bắt buộc không thể để trống". Xem hướng dẫn sử dụng php.net/manual/en/feft.empty.php
Halil Özgür
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.