После рефакторинга
Было бы хорошо предотвратить это в первую очередь.
Вы можете обнаружить такие ошибки рефакторинга, только запуская тесты после каждого шага рефакторинга. Эта ошибка также будет всплывать, потому что foo['blubb']
установлено определенное значение, и это должно вызвать нежелательный эффект в другом тесте — не только в тесте на логику сеттера.
Мы используем тесты, но иногда что-то упускаешь...
Да, довольно часто охват недостаточно высок. Вот почему наличие хорошего тестового покрытия является отправной точкой для любого рефакторинга.
Эти две строки не были зелеными в вашем отчете о покрытии:
if(!isset($this->bla['blubb'])) {
$this->foo['blubb'] = $value;
Также, пожалуйста, не придумывайте перезапись магических методов. Я не хочу иметь черту/абстракцию в каждом классе.
Вы исключили его, но это один из способов перехвата свойств: использование магической функции __set()
(для недоступных переменных) или property_exists()
, или использование Reflection*
классов для поиска.
Теперь, когда уже слишком поздно, вы хотите, чтобы другой инструмент перехватил ошибку, хорошо:
Инструмент должен будет проанализировать файл 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). Оценка контекста может найти множество распространенных ошибок кодирования. В конце вы можете построить отчет: говоря, что $this-›bla был доступен только 1 раз, и это указывает либо на то, что
- было введено динамически объявленное свойство, но никогда не использовалось повторно, с предложением удалить его или объявить как свойство класса.
- ИЛИ с добавленной оценкой контекста: что и когда эта переменная была доступна изнутри isset() - что был получен доступ к несуществующему ключу необъявленного свойства, без предварительного set() и т. д.
person
Jens A. Koch
schedule
13.01.2016
$this->bla
может быть определен в родительском классе. Codesniffer работает на уровне файла/токена, и если вы будете следовать стандартам кодирования PSR, он не будет знать структуру родительского класса (поскольку он находится в отдельном файле). - person weirdan   schedule 08.01.2016