Thông báo lỗi "Tiêu chuẩn nghiêm ngặt: Chỉ các biến mới được chuyển qua tham chiếu"


81
$el = array_shift($instance->find(..))

Đoạn mã trên bằng cách nào đó báo cáo cảnh báo tiêu chuẩn nghiêm ngặt, nhưng điều này sẽ không:

function get_arr(){
    return array(1, 2);
}
$el = array_shift(get_arr());

Vì vậy, khi nào nó sẽ báo cáo cảnh báo anyway?


1
$ Instance-> find (..) trả về gì?
Silver Light


Tôi nghĩ rằng các ví dụ (hoặc logic) có thể là tròn một cách sai lầm trong câu hỏi, vì ví dụ 2 ( get_arr()chức năng) không tạo ra các tiêu chuẩn nghiêm ngặt thông báo (thử nghiệm PHP 5.2 và PHP 5.5).
MrWhite

Câu trả lời:


93

Hãy xem xét đoạn mã sau:

error_reporting(E_STRICT);
class test {
    function test_arr(&$a) {
        var_dump($a);
    }
    function get_arr() {
        return array(1, 2);
    }
}

$t = new test;
$t->test_arr($t->get_arr());

Điều này sẽ tạo ra kết quả sau:

Strict Standards: Only variables should be passed by reference in `test.php` on line 14
array(2) {
  [0]=>
  int(1)
  [1]=>
  int(2)
}

Nguyên nhân? Các test::get_arr()phương pháp không phải là một biến và dưới chế độ nghiêm ngặt này sẽ tạo ra một cảnh báo. Hành vi này cực kỳ không trực quan vì get_arr()phương thức trả về một giá trị mảng.

Để khắc phục lỗi này ở chế độ nghiêm ngặt, hãy thay đổi chữ ký của phương thức để nó không sử dụng tham chiếu:

function test_arr($a) {
    var_dump($a);
}

Vì bạn không thể thay đổi chữ ký của array_shiftbạn, bạn cũng có thể sử dụng một biến trung gian:

$inter = get_arr();
$el = array_shift($inter);

7
@ user198729: Tôi cũng đang tìm lời giải thích hoặc bản sửa lỗi và nhận thấy bạn có thể sử dụng current () cho mục đầu tiên. Than ôi end () không hoạt động cuối cùng vì nó "chuyển con trỏ nội bộ đến phần tử cuối cùng". (array_reverse (someFunction ())) công trình hiện tại (có, đó là ngớ ngẩn)
MSpreij

1
Việc sử dụng currenttạo ra giả định rằng con trỏ mảng nằm ở phần tử đầu tiên. Nó có thể là một giả định hợp lệ trong hầu hết các trường hợp, nhưng một giả định cần chú ý.
cmbuckley

1
@leepowers Tất nhiên, sau đó sẽ là vấn đề tương tự như array_shift()ở chỗ nó hy vọng một tham chiếu đến sửa đổi :-)
cmbuckley

1
@ user198729 Bạn có thể tránh $intermediategiá trị bằng cách sử dụng thêm một cặp dấu ngoặc đơn. $el = array_shift( ( get_arr() ) );. Xem stackoverflow.com/questions/9848295/…
Chloe

1
@Chloe Đây là giải pháp tuyệt vời nhất mà tôi từng thấy để giữ cho mã đơn giản !! Cảm ơn bạn!
hargobind

7

$instance->find() trả về một tham chiếu đến một biến.

Bạn nhận được báo cáo khi bạn đang cố gắng sử dụng tham chiếu này làm đối số cho một hàm mà không cần lưu trữ nó trong một biến trước.

Điều này giúp ngăn ngừa rò rỉ bộ nhớ và có thể sẽ trở thành lỗi trong các phiên bản PHP tiếp theo.

Khối mã thứ hai của bạn sẽ gặp lỗi nếu nó được viết như thế (lưu ý &trong chữ ký hàm):

function &get_arr(){
    return array(1, 2);
}
$el = array_shift(get_arr());

Vì vậy, một bản sửa lỗi nhanh chóng (và không hay lắm) sẽ là:

$el = array_shift($tmp = $instance->find(..));

Về cơ bản, bạn thực hiện một phép gán cho một biến tạm thời trước và gửi biến đó dưới dạng một đối số.


Nó sẽ hoạt động ngay bây giờ (đã kiểm tra nó). Để trả về tham chiếu, bạn phải khai báo nó tại chữ ký phương thức, không phải câu lệnh trả về (lỗi của tôi).
Sagi

Không, tôi không thể thay đổi chữ ký. Biến trung gian của @ pygorex1 có thể giải quyết vấn đề này, nhưng nó có vẻ thừa, phải không?
user198729,

Tôi biết bạn không thể thay đổi chữ ký, chỉ cần giải thích cách nó xảy ra. Bạn phải sử dụng biến tạm thời (= trung gian), nhưng bạn có thể làm điều đó trong cùng một dòng. Nhìn vào đoạn mã thứ hai của tôi.
Sagi

4
Tôi cố gắng đoạn thứ hai của bạn, không working.It chỉ hoạt động trong một dòng riêng biệt
user198729

3
Thật. Phép gán trả về giá trị được gán . array_shift($tmp = $instance->find(..))gán giá trị của $instance->find(..)cho $tmpvà sau đó chuyển giá trị của phép gán cho array_shift()- điều này không giống với việc chuyển $tmpchính nó, vì vậy không tốt hơn tình huống ban đầu mà không có phép gán.
phils

6

Nguyên nhân của lỗi là do sử dụng hàm cấu trúc dữ liệu lập trình PHP nội bộ, array_shift () [php.net/end].

Hàm nhận một mảng làm tham số. Mặc dù ký hiệu và được chỉ ra trong nguyên mẫu của array_shift()trong sách hướng dẫn ", không có bất kỳ tài liệu cảnh báo nào theo định nghĩa mở rộng của hàm đó, cũng như không có bất kỳ lời giải thích rõ ràng nào rằng thông số trên thực tế được chuyển qua tham chiếu.

Có lẽ điều này được / hiểu /. Tuy nhiên, tôi không hiểu nên rất khó phát hiện ra nguyên nhân gây ra lỗi.

Sao chép mã:

function get_arr()
{
    return array(1, 2);
}
$array = get_arr();
$el = array_shift($array);

3

Mã này:

$monthly_index = array_shift(unpack('H*', date('m/Y')));

Cần được thay đổi thành:

$date_time = date('m/Y');
$unpack = unpack('H*', $date_time);
array_shift($unpack);


0

Chà, trong những trường hợp rõ ràng như vậy, bạn luôn có thể yêu cầu PHP ngăn chặn các thông báo bằng cách sử dụng "@" trước hàm.

$monthly_index = @array_shift(unpack('H*', date('m/Y')));

Nó có thể không phải là một trong những phương pháp lập trình tốt nhất để loại bỏ tất cả các lỗi theo cách này, nhưng trong một số trường hợp nhất định (như trường hợp này), nó có ích và có thể chấp nhận được.

Do đó, tôi chắc chắn rằng 'quản trị viên hệ thống' của bạn bạn sẽ hài lòng với một môi trường ít ô nhiễm hơn error.log.


Tôi không biết ai đã phản đối câu trả lời này, nhưng giải pháp được trình bày KHÔNG hoạt động và nó là một kỹ thuật tiêu chuẩn PHP. Thật đáng thất vọng ... Lần sau tôi không thể trả lời một câu hỏi nữa ... :(
Julio Marchi

5
Tôi cho rằng đó là do việc ngăn chặn thông báo lỗi không khắc phục được sự cố với mã. Bạn sẽ làm gì khi loại lỗi này thay đổi từ E_STRICT thành E_ERROR trong một bản phát hành PHP trong tương lai và mã của bạn bây giờ không chạy và cũng không tạo ra bất kỳ lỗi / đầu ra nào?
Luke

@TinoDidriksen, tôi hiểu và đồng ý với những lý do để khuyên bạn nên chống lại một số "thói quen xấu", đặc biệt là đối với các thế hệ mới. Tuy nhiên, tài nguyên tồn tại để được sử dụng khi (và nếu) an toàn để sử dụng và có thể áp dụng cho ngữ cảnh được đề xuất. Nếu bộ chặn lỗi "@" bị loại bỏ, nó sẽ bị xóa khỏi chính ngôn ngữ. Tương tự như "eval" (nó có thể là xấu, nhưng nó có mục đích của nó). Điều tôi phản đối không phải về việc sử dụng một số tài nguyên mà là sự khái quát của một lời khuyên. Trong trường hợp cụ thể được đề xuất, sẽ không có hại gì nếu sử dụng nó, thậm chí không cho mục đích gỡ lỗi.
Julio Marchi,
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.