Hướng dẫn phpstan variable might not be defined - biến phpstan có thể không được xác định

Thực đơn

Xem xét ví dụ này:

if (somethingIsTrue()) {
$foo = true;
} elseif (orSomethingElseIsTrue()) {
$foo = false;
} else {
$this->redirect('homepage');
}

doFoo($foo); // possibly undefined variable $foo

Nếu không có bất kỳ kiến ​​thức đặc biệt nào, chúng tôi có thể nghĩ rằng biến $foo có thể không được xác định trong trường hợp nhánh else được thực thi. Tuy nhiên, một số cuộc gọi phương thức cụ thể có thể được các nhà phát triển dự án nhận thức cũng như chấm dứt sớm - như một redirect() dừng thực thi bằng cách ném một ngoại lệ nội bộ.

Các phương thức này có thể được định cấu hình bằng cách chỉ định một lớp trên thể hiện chúng được gọi bằng cách sử dụng khóa tùy chọn earlyTerminatingMethodCalls trong tệp cấu hình như thế này:

parameters:
earlyTerminatingMethodCalls:
Nette\Application\UI\Presenter:
- redirect
- redirectUrl
- sendJson
- sendResponse

Điều tương tự áp dụng cho các chức năng toàn cầu đơn giản. Các chức năng chấm dứt sớm có thể được xác định bằng cách sử dụng khóa earlyTerminatingFunctionCalls, giống như chức năng này với chức năng trợ giúp toàn cầu redirect():

parameters:
earlyTerminatingFunctionCalls:
- redirect

Thẻ PHPDOC

parameters:
earlyTerminatingMethodCalls:
Nette\Application\UI\Presenter:
- redirect
- redirectUrl
- sendJson
- sendResponse
0 trên hàm hoặc phương thức có thể được sử dụng thay vì định cấu hình earlyTerminatingFunctionCalls hoặc earlyTerminatingMethodCalls.


Một vấn đề khác mà bạn có thể gặp phải là Phpstan không hiểu các biến được xác định có điều kiện như sau:

if ($foo) {
$var = rand();
}

// 200 lines later:

if ($foo) {
echo $var; // Variable $var might not be defined.
}

Điều này đã được Phpstan hiểu từ phiên bản 0.12,64. Vì vậy, nếu bạn vẫn đang gặp phải vấn đề này, hãy đảm bảo nâng cấp lên phiên bản mới nhất.

Chỉnh sửa trang này trên github

Xin chào, Phpstan không phàn nàn về các tình huống như thế này trong phạm vi gốc ở cấp 0 - khi biến được sử dụng bên ngoài lớp/chức năng.

Tất nhiên để tiến lên cấp 1, bạn cần thực hiện một số công việc :) Một cách để giải quyết điều này là có

parameters:
earlyTerminatingMethodCalls:
Nette\Application\UI\Presenter:
- redirect
- redirectUrl
- sendJson
- sendResponse
3 trên đầu tệp của bạn. Điều đó cho Phpstan biết rằng bạn chắc chắn các biến này được xác định khi bao gồm tệp.you're sure these variables are defined when the file is included.

Ngoài ra, bạn nên nhận ra rằng các mẫu mã này đã lỗi thời và ngày nay tốt nhất là viết mã theo kiểu OOP, nơi vị trí mà tất cả các biến đến từ đó, là rõ ràng nhờ chúng được định nghĩa là các tham số chức năng.

Những gì sẽ là giải pháp nhanh nhất cho chế độ sản xuất, mà không thay đổi mã nữa và ví dụ loại bỏ các khẳng định.

#3850 (bình luận)

parameters:
earlyTerminatingMethodCalls:
Nette\Application\UI\Presenter:
- redirect
- redirectUrl
- sendJson
- sendResponse
4 là tốt hơn

Chỉnh sửa: Bạn có thể cần phải rõ ràng hơn và sử dụng

parameters:
earlyTerminatingMethodCalls:
Nette\Application\UI\Presenter:
- redirect
- redirectUrl
- sendJson
- sendResponse
5, xem https://phpstan.org/r/1dc5f0ee-9de5-486f-AE37-3F3A444EFBE7F

Có thể "khẳng định" bị vô hiệu hóa bằng cách nào đó, ví dụ: Tôi không muốn mã này chạy trong chế độ sản xuất. Chỉ khi phát triển/thử nghiệm. Vì vậy, tôi đã thử

parameters:
earlyTerminatingMethodCalls:
Nette\Application\UI\Presenter:
- redirect
- redirectUrl
- sendJson
- sendResponse
6 và điều đó hoạt động. Tôi hoàn toàn hiểu rằng tệp chế độ xem của tôi có thể được gọi từ những nơi khác, và sau đó mọi thứ có thể thất bại vì không có gì đảm bảo rằng nó được gọi với các thông số dự kiến. Vì vậy, có nó có ý nghĩa từ quan điểm đó để sử dụng isset () hoặc khẳng định ().
So I tried
parameters:
earlyTerminatingMethodCalls:
Nette\Application\UI\Presenter:
- redirect
- redirectUrl
- sendJson
- sendResponse
6 and that works.
I full understand that my view file could be called from other places, and then everything can fail since there is no guarantee that it called with the expected params.
So yes it makes sense from that point of view to either use isset() or assert().

Bài kiểm tra thất bại: https://phpstan.org/R/5D05F528-AE08-47C1-8C4A-4988AA7131C3
https://phpstan.org/r/5d05f528-ae08-47c1-8c4a-4988aa7131c3

Với

parameters:
earlyTerminatingMethodCalls:
Nette\Application\UI\Presenter:
- redirect
- redirectUrl
- sendJson
- sendResponse
7 (cũng thất bại với các bài kiểm tra nghiêm ngặt-nhưng do khẳng định luôn là đúng) https://phpstan.org/r/b44f3534-3ce9-4763-A286
https://phpstan.org/r/b44f3534-3ce9-4763-a286-c7fae9343979

Với

parameters:
earlyTerminatingMethodCalls:
Nette\Application\UI\Presenter:
- redirect
- redirectUrl
- sendJson
- sendResponse
6 https://phpstan.org/r/f3122DF3-37AE-4138-8930-034C68E714BF
https://phpstan.org/r/f3122df3-37ae-4138-8930-034c68e714bf

Cấu trúc cuối cùng cũng rất khó xử, nhưng tôi tin rằng (tôi không thực sự biết, do đó tôi đang hỏi) nó sẽ có chi phí nhỏ nhất.believe ( I don't really know, hence I am asking) it would have the smallest overhead.