PHP言語はそのシンプルさと習得のしやすさで知られていますが、一部の初心者はしばしばパフォーマンスの低いPHPコードを書いてしまい、それがシステム全体の実行効率に深刻な影響を与えることがあります。この記事では、PHPプログラミングのテクニックと最適化をいくつかまとめました。PHPの初心者が以下のプログラミングテクニックをよく読んで、良いPHPプログラミング習慣を身につけることを願っています!

PHP 编程技巧与优化

PHPプログラミングのコツ63選

  • 1. PHPの組み込み関数をできるだけ多用する。
  • 2. 使用するechoの代わりにprint、そして使うechoの複数パラメータ(訳注:ピリオドではなくカンマを使うこと)を文字列連結の代わりに用いる。例えば
  • echo $str1,$str2;
    
  • 3. メソッドを細分化しすぎないこと。本当に再利用しようとしているコードがどれかをよく考えよう。
  • 4. 実行する際、forループの前に最大ループ数を決定し、ループごとに最大値を計算しないこと。
  • 5. 使わない変数、特に大きな配列をunsetして、メモリを解放する。
  • 6. すべてのデータ構造をクラスで実装する必要はない。配列も非常に有用である。
  • 7、 $row['id']の効率は$row[id]の7倍です。
  • 8. ファイルをインクルードする際は完全なパスを使用する。オペレーティングシステムのパスを解析するのに必要な時間が少なくなる。
  • 9. スクリプトの実行開始時刻(訳注:サーバー側がクライアントからのリクエストを受信した時点)を知りたいなら、$_SERVER['REQUEST_TIME']を使うのがtime()。
  • 10. 関数で正規表現と同じ機能を実現する場合、str_replace関数はpreg_replace関数より速いが、strtr関数の効率はstr_replace関数の4倍である。
  • 11. コードのインデントに注意する。
  • 12. 文字列置換関数が配列または文字を引数として受け取れ、かつ引数の長さがそれほど長くない場合、毎回引数として1文字を渡すような置換コードを追加で書くことを検討できる。1行のコードで配列を検索・置換の引数として受け取るのではなく。
  • 13. 選択分岐文(訳注:すなわちswitch case)を使うほうが複数のif,else if文を使うより良い。
  • 14. @でエラーメッセージを抑制するのは非常に非効率的である。
  • 15. Apacheのmod_deflateモジュールを有効にする。
  • 16. データベース接続は使用が終わったら閉じるべきである。
  • 18. エラーメッセージはコストが高い。
  • 19. forループ内で関数を使うのはできるだけ避ける。例えばfor ($x=0; $x < count($array); $x)ループごとにcount()関数が呼び出される。
  • 20. メソッド内でローカル変数をインクリメントするのが最速である。ほぼ関数内でローカル変数を呼び出すのと同じ速度である。
  • 21. グローバル変数のインクリメントはローカル変数のインクリメントより2倍遅い。
  • 22. オブジェクトのプロパティをインクリメントする(例:$this->prop++)のはローカル変数のインクリメントより3倍遅い。
  • 23. 未定義のローカル変数をインクリメントするのは、定義済みのローカル変数をインクリメントするより9〜10倍遅い。
  • 24. 関数内で呼び出さずにローカル変数を定義するだけでも速度が遅くなる(ローカル変数のインクリメントと同程度)。PHPはグローバル変数が存在するかどうかをチェックするからである。
  • 25. メソッド呼び出しは、クラス内で定義されたメソッドの数とは無関係であるようだ。(テストメソッドの前後に)10個のメソッドを追加したが、パフォーマンスに変化はなかったからである。
  • 26. 派生クラスのメソッドは、基底クラスで定義された同じメソッドよりも速く実行される。
  • 27. 1つの引数を持つ空の関数を呼び出すのにかかる時間は、ローカル変数のインクリメントを7〜8回実行するのと同じである。同様のメソッド呼び出しは、ローカル変数のインクリメント15回分に近い時間がかかる。
  • 28. 文字列を囲むときは二重引用符の代わりに一重引用符を使うと少し速くなる。PHPは二重引用符で囲まれた文字列内で変数を探すが、一重引用符では探さないからだ。もちろん、文字列内に変数を含める必要がない場合に限る。
  • 29. を使ってecho複数の文字列を出力する際、ピリオドの代わりにカンマで文字列を区切ると速度が速い。
  • 30. ApacheがPHPスクリプトを解析する時間は、静的HTMLページを解析するより2〜10倍遅い。できるだけ静的HTMLページを多用し、スクリプトを減らすこと。
  • 31. スクリプトがキャッシュされない限り、呼び出しのたびに再コンパイルされる。PHPキャッシュメカニズムを導入すると、通常25%〜100%のパフォーマンス向上が見込め、コンパイルのオーバーヘッドを回避できる。
  • 32. できるだけキャッシュを行い、memcachedを使用できる。memcachedは高性能なメモリオブジェクトキャッシュシステムで、動的Webアプリケーションの高速化やデータベース負荷の軽減に使える。オペコード(OP code)のキャッシュに非常に有用で、スクリプトがリクエストごとに再コンパイルされるのを防ぐ。
  • 33. 文字列を操作し、その長さが何らかの要件を満たすかどうかを検査する必要がある場合、当然strlen()関数を使うだろう。この関数は計算を一切行わず、zval構造体(PHP変数を格納するCの組み込みデータ構造)に格納された既知の文字列長を返すだけなので、実行はかなり速い。しかし、strlen()は関数であるため、多少遅くなる。関数呼び出しは、文字の小文字化(訳注:関数名の小文字化。PHPは関数名の大文字小文字を区別しない)、ハッシュ検索など、呼び出された関数とともに実行される多くのステップを経るからである。状況によっては、isset()テクニックを使ってコードの実行を高速化できる。
  • if (strlen($foo) < 5) { echo "Foo is too short"; }
    if (!isset($foo{5})) { echo "Foo is too short"; }
    
  • 34. クラスのメソッドをstaticと定義できるなら、できるだけstaticと定義する。速度が約4倍向上する。
  • 35. 使用しないことarray_key_exists、使うのはisset配列内にキーが存在するかどうかを判断するため
  • 36. 使用を避ける__set,__getなどのマジックメソッド
  • 37. 使用するinclude/requireの代わりにinclude_once/require_once、そしてできるだけ絶対パスを使用する
  • 38. しないことcount/strlen/sizeofなどをforループの条件文に置く
  • 39. できるだけ使用するforeachの代わりにfor/while
  • 40. 文字列に変数を含める場合は、一重引用符ではなく二重引用符を使用する。例:
  • echo "hi, $name, nice to meet you";
    
  • 41. 小さなファイルを読む場合はfread、大きなファイルを読む場合はfile_get_contents、特大のファイルの場合はfseek
  • 42. 使用するip2long()とlong2ip()関数でIPアドレスを整数に変換して格納すると、特定のアドレスがセグメント内にあるかどうかの計算が簡単になり、検索とソートの速度も向上する。
  • 43. メールアドレスを検証する際にcheckdnsrr()関数でドメインが存在するかどうかを検証する。この組み込み関数は、指定されたドメインがIPアドレスに解決できることを確認できる。
  • 44. 捨てることを検討するmysql_*シリーズ関数を改良版のmysqli_*シリーズ関数に変更する
  • 45. 三項演算子を愛用することを覚える
  • 46. プロジェクトで再利用可能な部分があると感じたら、次のコードを書く前にPEARに既に存在するかどうか確認しよう。このオンラインリポジトリには400以上の再利用可能なプログラム断片が含まれており、これらのプログラム断片はすぐにあなたのプログラムで使える。プロジェクトが本当に特別でない限り、時間を節約できるPEARパッケージを必ず見つけられるだろう。
  • 47. 使ってhighlight_file()フォーマットされた美しいソースコードを自動的に出力する
  • 48. 使用するerror_reporting(0)関数で、ユーザーに潜在的に機密性の高いエラー情報を見せないようにする。理想的な状況では、公開サーバーではphp.iniで完全に無効にするべきだ。しかし、共有Webサーバーを使用している場合、自分専用のphp.iniファイルがないので、その場合はすべてのスクリプトの最初の行の前にerror_reporting(0)
  • 49. データベースに非常に大きな文字列を保存する前にgzcompress()とgzuncompress()を使って文字列を明示的に圧縮/解凍する
  • 50. 「参照」でパラメータを渡す方法によって、関数から複数の戻り値を得る
  • 51. 「マジッククォート」とSQLインジェクションの危険性を完全に理解する。SQLインジェクションを防ぐ最も簡単な方法:php.iniでmagic_quotesをOnに設定し、mysql_real_escape_string()関数でエスケープする
  • 52. データベース接続は使用が終わったら閉じるべきであり、持続的な接続(long connection)は使わないこと。
  • 53. グローバル変数は、使い終わったらunset()すべきである。
  • 54. ユーザーが送信したデータを信頼してはいけない。必ずhtmlentities()或 htmlspecialchars()でエスケープする
  • 55. 変数の$iのインクリメントまたはデクリメントを行う場合、$i++は++$iより少し遅い。この違いはPHP特有であり、他の言語には当てはまらない。そのため、CやJavaのコードを修正してすぐに速くなることを期待してはいけない。無駄である。++$iの方が速いのは、わずか3つの命令(オペコード)しか必要としないからである。$i++は4つの命令を必要とする。後置インクリメントは実際には一時変数を生成し、その一時変数が後でインクリメントされる。一方、前置インクリメントは元の値に直接インクリメントする。
  • 56. 何でもかんでもオブジェクト指向(OOP)にする必要はない。オブジェクト指向はしばしばオーバーヘッドが大きく、各メソッドやオブジェクトの呼び出しは多くのメモリを消費する。
  • 57. コード内に多くの時間を消費する関数が存在する場合、C拡張の形で実装することを検討できる。
  • 58. コードをプロファイリング(評価検査)しよう。プロファイラは、コードのどの部分がどれだけの時間を消費しているかを教えてくれる。Xdebugデバッガにはプロファイラが含まれており、プロファイリングは全体的にコードのボトルネックを示してくれる。
  • 59、mod_zipはApacheモジュールとして使用でき、データを即時に圧縮し、データ転送量を80%削減できます
  • 60、ファイル操作はできるだけ少なく行いましょう。PHPのファイル操作効率も低くはありませんが
  • 61、最適化Select SQL文は、可能な場合にはできるだけ少なく行うInsert、Update操作
  • 62、ループ内部では変数を宣言しないでください。特に大きな変数:オブジェクト(これはPHPだけに注意すべき問題ではないですよね?)
  • 63、多次元配列にはループのネストで代入しないようにしましょう
  • 64、……

関連リソース