2015-08-13 21 views
8

Sau một tái cấu trúc, chúng tôi đã có một cái gì đó như thế này trong một trong các lớp học của chúng tôi:Làm thế nào để phát hiện các lĩnh vực declarated động trên các đối tượng với codesniffer trong PHP

class FooBar 
{ 
    // $foo was $bla before 
    private $foo; 

    public function setBlubbOnArrayOnlyOnce($value) 
    { 
     // $this->bla was forgotten during refactoring. Must be $this->foo 
     if(!isset($this->bla['blubb'])) { 
      $this->foo['blubb'] = $value; 
     } 
    } 
} 

Vì vậy, vào cuối $ this-> foo [ 'blubb' ] luôn được thiết lập, không chỉ một lần. Điều này xảy ra do các phương pháp ma thuật của PHP. Chúng tôi không muốn nó có thể truy cập các lĩnh vực động, vì vậy tôi nghĩ rằng tôi chỉ cần thêm một quy tắc mã hóa. Nhưng tôi không tìm thấy và hỏi tôi tại sao.

PHPStorm hiển thị trường được khai báo tự động ở đó, nhưng tôi muốn điều này tự động bị lỗi với mã số (hoặc điều gì đó tương tự) trong chu kỳ triển khai của chúng tôi.

Có ai có ý tưởng về điều này không? Có quy tắc nào tốt không? Tôi có nên viết của riêng tôi và làm thế nào? Hoặc nó sẽ là thực hành xấu để vô hiệu hóa nó?

Tuyên bố từ chối trách nhiệm: Chúng tôi sử dụng các thử nghiệm, nhưng đôi khi bạn bỏ lỡ mọi thứ ... Sẽ tốt hơn nếu bạn ngăn điều này ngay từ đầu. Ngoài ra, xin đừng đến với việc ghi đè lên các phương pháp ma thuật. Tôi không muốn có một đặc điểm/trừu tượng bất cứ điều gì trong mỗi lớp.

+1

Bạn có thể tìm kiếm các biến không xác định, vì $ this-> bla sẽ không được khai báo? Bạn có thể phải mở rộng mã trong PHPCodeSniffer. –

+0

Tôi đang cố gắng, nhưng tôi đã hy vọng một cách rõ ràng và dễ dàng để làm điều đó – Kasihasi

+1

Bạn đã yêu cầu trên Squizlabs (http://www.squizlabs.com/) hoặc GitHub của họ (https://github.com/squizlabs/PHP_CodeSniffer) như Greg Sherwood đã khá nhạy cảm với các câu hỏi trong quá khứ. –

Trả lời

2

Đây không phải là vấn đề về mã hóa hoặc phpstorm. Và bạn không thể sửa vấn đề này với mã hóa hoặc IDE. IDE, codesniffer, phpdocumentor, v.v. - đây là phân tích "tĩnh". Và để phân tích động, bạn có thể sử dụng ví dụ: phpunit.

Nếu bạn muốn kiểm tra sự tồn tại của thuộc tính, bạn phải sử dụng hàm property_exists().

class X 
{ 
    public function __get($name) 
    { 
     $this->{$name} = null; 
     return $this->{$name}; 
    } 
} 

$x = new X(); 
var_dump(property_exists($x, 'foo')); // false 
var_dump($x->foo); // NULL 
var_dump(property_exists($x, 'foo')); // true 

Hoặc có thể bạn có thể sử dụng phản ánh cho tài sản http://php.net/manual/en/class.reflectionproperty.php

Nếu bạn muốn kiểm tra cho "isset" bạn phải biết:

var_dump(isset($x), $x); // false + NULL with notice 
$x = null; 
var_dump(isset($x), $x); // false + NULL 
unset($x); 
var_dump(isset($x), $x); // false + NULL without notice 

Khi bạn shure đối với trường hợp này kiểm tra xem bạn có thể sử dụng isset()

Nhưng trước hết bạn nên kiểm tra sự tồn tại của thuộc tính. Nếu không, bạn có thể có hành vi không xác định mã của bạn.

+0

Nó không phải là về việc phát hiện nếu '$ this-> bar ['' anyStringValue' được định nghĩa (có thể thậm chí không thể có trong phân tích tĩnh), đó là về phát hiện rằng $ this-> bar không được định nghĩa (nữa). – maxhb

+0

@ maxhb Câu trả lời của tôi bao gồm về điều này. – Deep

2

Sau một refactoring

Nó sẽ là tốt để ngăn chặn điều này ở nơi đầu tiên.

Bạn chỉ có thể bắt các loại lỗi tái cấu trúc này bằng cách chạy thử nghiệm sau mỗi bước tái cấu trúc. Lỗi này cũng sẽ bong bóng lên, bởi vì foo['blubb'] được đặt thành một giá trị cụ thể và điều này sẽ gây ra một hiệu ứng không mong muốn trong một thử nghiệm khác - không chỉ trong thử nghiệm cho logic setter.

Chúng tôi sử dụng các bài kiểm tra, nhưng đôi khi bạn bỏ lỡ những thứ ...

Vâng, Khá phổ biến là bảo hiểm không đủ cao của nó. Đó là lý do tại sao có một phạm vi kiểm tra tốt là điểm khởi đầu cho tất cả các cấu trúc lại.

Hai dòng này không phải là "xanh" trong báo cáo bảo hiểm của bạn:

if(!isset($this->bla['blubb'])) { 
     $this->foo['blubb'] = $value; 

Ngoài ra, xin đừng đưa ra ghi đè lên các phương pháp kỳ diệu. Tôi không muốn có một đặc điểm/trừu tượng bất cứ điều gì trong mỗi lớp.

Bạn đã loại trừ nó, nhưng đó là một cách để bắt các thuộc tính: bằng cách sử dụng chức năng kỳ diệu __set() (ví vars không thể tiếp cận) hoặc property_exists() hoặc việc sử dụng Reflection* lớp học để tìm.


Bây giờ, điều đó quá muộn, bạn muốn một công cụ khác để bắt lỗi, ok:

Công cụ này sẽ cần phải phân tích các file PHP và cha mẹ của nó (vì phạm vi biến) và tìm $this->bla mà không có khai báo biến số public|private|protected (thuộc tính lớp) trước. Điều này sẽ không cho biết loại lỗi chính xác, chỉ rằng "bla" được truy cập mà không cần khai báo.

Có thể thực hiện điều này dưới dạng quy tắc CodeSniffer.

Bạn cũng có thể dùng thử http://phpmd.org/ hoặc https://scrutinizer-ci.com/. Và, trong trường hợp bạn đang sử dụng PHP7: https://github.com/etsy/phan

tl; tr

của nó phức tạp để xác định lỗi chính xác và ngữ cảnh của nó mà không cần chạy, đánh giá và phân tích các mã cơ bản. Chỉ cần suy nghĩ về "tên biến động" và bạn biết tại sao: bạn thậm chí không biết tên của thuộc tính bằng cách xem mã nguồn, bởi vì nó xây dựng động trong luồng chương trình. Một máy phân tích tĩnh sẽ không bắt được.

Máy phân tích động phải theo dõi tất cả mọi thứ, tại đây $this-> truy cập và sẽ đưa bối cảnh vào tài khoản:! Isset (x). Đánh giá bối cảnh có thể tìm thấy rất nhiều lỗi mã hóa phổ biến. Cuối cùng, bạn có thể tạo báo cáo: nói rằng $ this-> bla chỉ được truy cập 1 lần và cho biết rằng

  • thuộc tính được khai báo động, nhưng không bao giờ được sử dụng lại, với đề xuất rằng bạn có thể thả nó hoặc khai báo nó như là thuộc tính lớp
  • HOẶC có thêm đánh giá ngữ cảnh: và khi biến này được truy cập từ bên trong một isset() - một khóa không tồn tại của thuộc tính không khai báo đã được truy cập, mà không có trước set(), v.v.
1

Bây giờ trong năm 2017, bạn đang tìm kiếm tool PHPStan. Tôi liên kết giới thiệu ngắn mà tôi đã viết cho người dùng lần đầu tiên.

Nó thực hiện chính xác những gì bạn cần!

Các vấn đề liên quan