2015-08-13 25 views
8

檢測動態declarated領域上的對象與codesniffer一個重構之後,我們有這樣的事情在我們的一類:如何在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; 
     } 
    } 
} 

所以最終$這個 - >富[「blubb」 ]總是被設置,不僅一次。 這是因爲PHP的神奇方法。我們不希望它可以動態訪問字段,所以我想我只是添加了一個codesniffer規則。但我沒有找到任何問題,並問我爲什麼。

PHPStorm顯示一個聲明動態通知的字段,但我希望這會在我們的部署週期中自動失敗,並顯示codesniffer(或類似內容)。

有沒有人有這個想法?有一個很好的規則嗎?我應該寫我自己的和如何?或者禁用它會是不好的做法嗎?

聲明:我們使用測試,但有時您會錯過一些事情......首先應該避免這種情況。另外,請不要想出覆蓋魔術方法。我不想在每個班級都有特質/抽象。

+1

你可以尋找未定義的變量,因爲$ this-> bla不會被聲明嗎?您可能必須在PHPCodeSniffer中擴展代碼。 –

+0

我在嘗試,但我希望有一個明顯而簡單的方法來做到這一點 – Kasihasi

+1

你問過Squizlabs(http://www.squizlabs.com/)或他們的GitHub(https://github.com/squizlabs)嗎?/PHP_CodeSniffer),格雷格舍伍德對過去的問題做出了相當的迴應。 –

回答

2

這不是一個codeniffer或phpstorm問題。你不能用Codeniffer或IDE來解決這個問題。 IDE,codesniffer,phpdocumentor等 - 這是「靜態」分析。而對於動態分析,您可以使用例如PHPUnit的。

如果你想檢查屬性的存在,你必須使用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 

或者,你可以使用反射財產http://php.net/manual/en/class.reflectionproperty.php

如果你想檢查「isset」你必須知道:

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 

當你舒爾針對這種情況檢查您可以的使用isset()

但你應該總是首先檢查財產的存在。否則,你可能會有未定義的代碼行爲。

+0

它不是檢測是否定義了$ this-> bar [''anyStringValue'(可能在靜態分析中不可能),它是關於檢測$ this-> bar沒有被定義(再)。 – maxhb

+0

@maxhb我的回答包括這個。 – Deep

2

一個重構

後這將是很好的避免這種情況擺在首位。

您只能通過在每個重構步驟之後運行測試來捕獲這些類型的重構錯誤。這個錯誤也會冒泡,因爲foo['blubb']被設置爲一個特定的值,並且這會在另一個測試中引起不希望的效果 - 不僅在測試設置邏輯中。

我們使用的測試,但有時你錯過的東西...

是的,它很普遍的覆蓋率不夠高。 這就是爲什麼擁有良好的測試覆蓋率是所有重構的出發點。

這兩條線是不是「綠色」在您的覆蓋率報告:

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

而且,請不要拿出覆蓋魔術方法。我不想在每個班級都有特質/抽象。

您已經排除了,但是這是趕上屬性的一種方法:使用神奇的功能__set()(對於無法訪問瓦爾)或property_exists()或使用Reflection*類的發現。現在


,其爲時已晚,你想另一種工具來捕獲錯誤,OK:

該工具將需要解析PHP文件及其父母(因變量範圍),並找到$this->bla沒有先前的public|private|protected變量(類屬性)聲明。這並不表示錯誤的確切類型,只是「bla」在沒有聲明的情況下被訪問。

它可能實現這CodeSniffer規則。

您也可以試一試http://phpmd.org/https://scrutinizer-ci.com/。 而且,如果你正在使用PHP7:https://github.com/etsy/phan

TL,TR

其複雜的,以確定確切的錯誤和不運行,評估和分析的基礎代碼上下文。考慮一下「動態變量名稱」,你知道爲什麼:你甚至不知道源代碼的屬性名稱,因爲它在程序流程中動態構建。一個靜態分析器將無法捕捉到。

一個動態分析器必須跟蹤所有東西,在這裏$this->訪問,並將考慮上下文:!isset(x)。上下文評估可以發現許多常見的編碼錯誤。最後,你可以建立一個報告:稱$這個 - >喇嘛被訪問只有1次,並表示要麼

  • 動態聲明的屬性被引入,而且永不再使用,建議您可能會刪除它或將其聲明爲類屬性
  • 或者帶有添加的上下文評估:當該變量從isset()內部訪問時 - 訪問非聲明屬性的不存在的鍵時,沒有先驗()等
1

現在在2017年,你在尋找tool PHPStan。我鏈接了我爲第一次使用用戶編寫的簡短介紹。

它完全符合您的需求!