注釈
この記事の第2部は計画されていませんでしたが、トピックが共鳴したため、続行できます。
そのため、大規模プロジェクトでは静的コード分析が必要であり、PHPプロジェクトも例外ではありません。 実際、静的解析ツールを導入するための問題と方法論は、たとえばC ++と同じです 。
静的分析ツールを毎日使用することで、エラーの数を大幅に削減できるだけでなく、コード全体の品質を向上させることができます。これを実際に示すことがこの記事の目的です。
最小限の時間投資(および最大の利益)で何を見つけて修正できるかについて、以下で説明します。
ツール
ツールからは、PhpStormの拡張機能としてインストールされているPhp Inspectionsアナライザー(EA拡張)を使用します。
ソースコードを修正するためのルーチンを自動化するために、 PHP CS Fixerを使用できます。特に、Php Inspections(EA Extended)の一部がCS Fixer(たとえば)に追加されるためです。 このユーティリティを見てみる価値があります。コードを自動的に修正し、多くの時間を解放し、コードを手動で修正することでエラーを起こす可能性を減らします。
もちろん、アナライザーを盲目的に信頼しないでください。プロジェクトのセマンティクスは重要なことです。 変更を行う前に、コードがテストで覆われていることを確認してください-静的アナライザーを使用するには、特定の安全技術が必要です。
欠陥の例
参照の不一致とメモリの問題
長いプロファイリングなしでこのタイプの問題を見つける可能性は非常に低いですが、静的分析はそのような場所を明らかにします。 この問題は、メモリ消費の最適化が実行された大規模なシステムおよびフレームワークに存在します。
理想的には、もちろん、開発者は診断メッセージに気づき、そのようなコードは表示されません。 検査はプラグインの次のリリースでのみ行われることを予約します。
namespace Symfony\Component\HttpFoundation\Session\Attribute; class NamespacedAttributeBag extends AttributeBag { ... public function get($name, $default = null) { /* * protected function &resolveAttributePath($name, $writeContext = false); * reference mismatch, */ $attributes = $this->resolveAttributePath($name); ... } ... }
あるべき姿:
public function get($name, $default = null) { $attributes = &$this->resolveAttributePath($name); ... }
Foreach、参照による値と非自明なエラー
foreachの特性は、独自のスコープを作成せず、変数が親スコープに残ることです。 したがって、値を参照として宣言すると、明らかな理由もなく配列の最後の値が変更されたときに非常に不快なバグが発生する可能性があります。
静的解析により、最初のパスで既にそのような場所が明らかになります。
namespace Symfony\Component\Console\Descriptor; class ApplicationDescription { ... private function sortCommands(array $commands) { ... foreach ($namespacedCommands as &$commands) { ksort($commands); } /* * - $commands, * $namespacedCommands */ return $namespacedCommands; } ... }
あるべき姿:
private function sortCommands(array $commands) { ... foreach ($namespacedCommands as &$commands) { ksort($commands); } unset($commands); ... return $namespacedCommands; }
マイクロ最適化
ここでは、最適ではないコード例を示しますが、それらの仕事は行います。
私の観察によると、このようなコードは、初心者の開発者を含むチームメンバーの定期的な変更中にシステムに表示されます。
開発者の能力を笑って話し合うことはできますが、建築家やチームリーダーは、そのような場所を不必要に批判することなく自分で修正する方が良いです。チームは主なタスクを評価し、集中します。
// if (false !== strpos($lang, '-')) - if (strstr($lang, '-')) { ... } // $cast = (int) $value - $cast = intval($value); // return (float) $value - return floatval($value); // $this->ignore |= static::IGNORE_DOT_FILES - $this->ignore = $this->ignore | static::IGNORE_DOT_FILES; // if (!in_array(static::$availableOptions[$option], $this->options)) - if (false === array_search(static::$availableOptions[$option], $this->options)) { ... } // ++$calls[$id] - $calls[$id] += 1; // if ('root' === get_current_user()) - if (in_array(get_current_user(), array('root'))) { ... } // if (array_key_exists($id, $container->getAliases())) - if (in_array($id, array_keys($container->getAliases()))) { ... } // return '' === $relativePath ? './' : $relativePath - return (strlen($relativePath) === 0) ? './' : $relativePath;
デッドコード
場合によっては、単純なアナライザーでは気付かないリファクタリングアーティファクトを見つけることができます。
namespace Symfony\Component\Security\Acl\Dbal; class MutableAclProvider extends AclProvider implements MutableAclProviderInterface, PropertyChangedListener { ... private function updateNewFieldAceProperty($name, array $changes) { ... // $currentIds = array(); foreach ($changes[1] as $field => $new) { for ($i = 0, $c = count($new); $i < $c; $i++) { ... if (null === $ace->getId()) { ... } else { // $currentIds[$ace->getId()] = true; } } } } ... }
結論の代わりに
記事の例(およびそれらはすべてSymfony2のPRの一部)が、プロジェクトを再度確認し、日常業務に静的分析ツールを導入する動機付けになることを願っています。
5〜10歳で「奇妙な」エラーをクリーンアップして排除するために多くのリソースを必要とする大規模な商用システムでは、PHPインスペクション(EA拡張)およびPHP CS Fixerは毎日あなたにとってかけがえのないツールになります。
オープンソースについては、 Scrutinizer CIとSensio Labs Insightsについてお知らせします。これは、以前の2つのツールと併用できる非常に便利なツールです。