[PHP-users 9232] Re: (メザコ?)クラス関数とオブジェクト関数で同一名を使うには?

Mashiki php-users@php.gr.jp
Thu, 08 Aug 2002 09:54:17 +0900


 Mashikiです。

しょうなりさん、情報ありがとうございます。

>目的のクラスとまったく関係ないオブジェクト内から
>目的のクラス内で isset($this) したということですね?
>class A {
> function A () {
>  print get_class($this)." : "; // class名の出力
>  print (isset($this)) ? "OBJECT" : "CLASS";
>  print "<BR>";
> }
>}
>
>class B {
> function B () {
>  A::A();
> }
>}
>
>A::A();
>$OB = new B;

 最初は、ふ〜んこんなこともできるんだ。ひまがあったら
ためしてみよっっと思って読み流していたのですが、僕が遭遇
した状況はこれが原因のようです。

>先日僕も気付いて、多重継承みたいなことができて便利って
>思っていました。
>(class A のメソッドで class B のプロパティを操作できます)

便利って言うよりすごく怖いですね。
ひどく直感に逆らう仕様と感じます。

僕が書いたのはDBのコネクションとエラー処理を管理するクラスで、
query()というメソッドとPEARのDBを格納するオブジェクト変数$dbを
用意していました。

query()はオブジェクト関数として呼ばれていればそのオブジェクトが
持っているDBで、クラス関数として呼ばれていればデフォルトのDBで、
SQLを実行するメソッドでした。

簡単に書くとこんな感じです。

class ConnectDB {
  var $db;
  
  function ConnectDB($DSN) {
    $db = DB::connect($DSN);
  }
  
  function &query($sql) {
    global $default_ConnectDB;

    if (isset($this)) {
      $dbConn =& $this;
    } else {
      $dbConn =& $default_DB_connect;
    }
    return $dbConn->db->query($sql);
  }
}

これをクラス関数として呼び出す場合、クラス内でない通常の関数や
関数の外側の通常のコードから呼び出す場合には普通に機能しますが、
他のオブジェクトの中の関数から呼び出された場合、そのオブジェク
トには、変数dbは無いのでエラーとなってしまいます。
デバッグの途中でこの関数の最初にprint_r($this)を入れてみたところ
まったく関係ないクラスの情報が出てきてしまい最初のメールをしました。

再現させようといろいろ試したのですが、オブジェクト関数から呼ぶ
というのは気が付きませんでした。

まとめると

isset($this)はオブジェクト関数として呼ばれた場合と
任意のクラスのオブジェクトからクラス関数として呼ばれた
場合に真になり、全てのオブジェクトの外側から呼ばれた
場合に偽になるということですか。


クラスの再利用を考えるとisset($this)による判断は避けたほうが
安全みたいですね。


PEARクラスの「静的メソッドとして PEAR::setErrorHandling()をコール」
する場合も必ずコードの一番外側の階層から呼ばないとうまく機能しない
ようですね。

$thisの仕様は納得がいかないのですが、しょうなりさんのおかげで
うまくいかない理由は理解できました。
本当にありがとうございました。