Locked History Actions

php/SaneTips

PHPプログラムを少しでもまともにするためのTIPS

以下は基本的にPHP 5.3以上が対象。

すべてのエラーを検出し、すべてのエラーを表示する

検出できるものはすべて検出する。これを行うには、/etc/php.iniにて

error_reporting = -1
display_errors = On

としておく。

インクルードはrequire_onceのみを使用する

include, include_once, requireはほとんどの場合必要無い。 ほぼ常にrequire_onceのみを使用する。

できる限りタイプヒンティングを使用する

$worldがWorldクラスのオブジェクトであることがわかっているなら、

class Sample {
  public function hello($world);
}

ではなく、

class Sample {
  public function hello(World$world);
}

とする。

未定義のメンバ変数へのアクセスを検出する

ひどいことに、PHPのオブジェクトは未定義のメンバ変数に平気でアクセスできてしまう。 このデタラメな言語仕様により、スペルミスをしてもそれになかなか気がつかないということが起こりうる。

class Sample {
 public $a;
}
$sample = new Sample();
$sample->b = 123;
print $sample->b;

以下のようなクラスを作成しておき、すべてのクラスをこのサブクラスとすることにより、未定義のメンバ変数へのアクセスをチェックすることができる。

/**
 * PHPのオブジェクトは未定義のメンバ変数(プロパティ)にアクセスしても警告さえでない。
 * 特に代入の際にスペルミスすると、いつまでも間違いに気が付かないということがありうる。
 * このクラスでは、代入及び参照の際にそのメンバ変数が定義されていることを確認する。
 * この仕組みは実行速度に響くと思われるので、本番環境ではこれらのメソッドを削除することが望まれる。
 */
class StrictCheckClass {
  
  /** メンバ変数参照時にその変数が定義済であることをチェックする */
  public function __get($name) {
    if (property_exists($this, $name)) return;
    $this->propertyNotFound($name);
  }
 
  /** メンバ変数への代入時にその変数が定義済であることをチェックする */
  public function __set($name, $val) {
    if (property_exists($this, $name)) return;
    $this->propertyNotFound($name);
  }  
    
  /** 指定された名前のメンバ変数が存在しないことを通知し、スタックトレースを表示する */
  private function propertyNotFound($name) {
    $className = get_class($this);
    print "property \$$name not found in class '$className'\n";    
    try {
      throw new Exception();
    } catch (Exception $e) {
      print $e;
    }    
  }
}

class Sample extends StrictCheckClass {
  public $a;
}

もちろん、このようなことをすると実行速度は遅くなると思われるが、少なくとも開発環境では上述の定義を行っておき、 本番環境ではこれらのメソッドを削除するような工夫をすればよい。