[PHP] クラス関連の関数など

PHPによるWebアプリケーションスーパーサンプル 第2版を読んでクラスを復習した内容についてのメモ:クラス関係の関数などについて:get_class_methods, get_class_vars, get_object_vars, get_declared_classes, class_exists, method_existsなど。

復習用メモ

やっぱり最初は何も見ずに思い出すべし

関数は引数や返り値、注意点を覚えておこう。

  • PHP5でプロパティの定義に var 修飾子を使用するとE_STRICTエラーは出る?出ない?
  • 定義済みのクラスを取得する方法は?
  • クラスおよびインスタンスの全メソッドを取得する方法は?
  • クラスおよびインスタンスの全プロパティを取得する方法は?
  • クラスが存在するかどうか調べる方法は?
  • クラスのメソッドが存在するかどうかを調べる方法は?
  • インスタンスがどのクラスのものかを調べる方法は?
  • メソッドがコール可能かどうかを調べる方法は?
  • その他思いつく関数を挙げてみるべし

参考

某サイトでPHPの良書とオススメされてたので読んでいる本。値段が高めで躊躇したけど買ってみた。 PHPによるWebアプリケーションスーパーサンプル 第2版

PHP5でプロパティの定義に var 修飾子を使用するとE_STRICTエラーは出る?出ない?

プロパティをvar修飾子で宣言するときのE_STRICTレベルのエラーについては残り一年! PHP4からPHP5への移行:第1回 移行前の基礎知識|gihyo.jp … 技術評論社を読むべし。間違ったこと覚えてた…5.1.3からは表示されないんだね

オブジェクトのメソッドを取得する

<php
class A
{
  public function pub(){}
  protected function pro(){}
  private function pri(){}
}

var_dump($a = get_class_methods("A"));
$a !== get_class_methods(new A) ?: print("同じだよ");

結果

array
  0 => string 'pub' (length=3)

同じだよ

get_class_methods はインスタンスに対しても使えるので注意ね。PHP4.06以前はダメらしいけどもね。抽象メソッドも取得できる。

オブジェクトのプロパティを取得する

<?php
class A
{
  var $var;
  public $public;
  protected $protected;
  private $private;
}

var_dump(get_class_vars("A"));
get_class_vars(new A);

結果

array
  'var' => null
  'public' => null

( ! ) Warning: get_class_vars() expects parameter 1
 to be string, object given in *** on line 11

get_class_vars でクラスのプロパティ名と初期値を取得できる。引数は文字列だよ。

class A
{
  public $pub;
  private $pri;
}
$a = new A;
$a->b = "foo";
$a->c->d = "bar";
$a->e = new stdClass;
$a->e->f = "baz";

var_dump(get_object_vars($a));

結果

( ! ) Strict standards: Creating default object
 from empty value in *** on line 8

array
  'pub' => null
  'b' => string 'foo' (length=3)
  'c' =>
    object(stdClass)[2]
      public 'd' => string 'bar' (length=3)
  'e' =>
    object(stdClass)[3]
      public 'f' => string 'baz' (length=3)

これE_STRICTエラー出るのか

定義済みの全クラスを取得する

<?php
$default = get_declared_classes();
// var_dump($default) 定義済みクラスが羅列される

class A{}
class B{}
class C{}
foreach(get_declared_classes() as $v)
{
  if(!in_array($v, $default, true))
  {
    $result[] = $v;
  }
}
var_dump(isset($result));

結果

boolean false

あれぇ?

<?php
$default = get_declared_classes();

function x(){
  class A{}
  class B{}
  class C{}
}
x();
foreach(get_declared_classes() as $v)
{
  if(!in_array($v, $default, true))
  {
    $result[] = $v;
  }
}
var_dump($result);

結果

array
  0 => string 'A' (length=1)
  1 => string 'B' (length=1)
  2 => string 'C' (length=1)

クラスはコンパイル時に定義されるから前のコードじゃ意味ないわな

メソッドが存在するかどうかの判定

<?php
function __autoload($class_name){
  echo $class_name;
}
var_dump(method_exists("A", "B"));
var_dump(method_exists("A", "C"));
var_dump(method_exists("D", "D"));

abstract class A
{
  abstract protected function b();
}

結果

boolean true
boolean false
D
boolean false

存在しないクラスを第一引数に入れると__autoload()がコールされる。可視性には影響されない。あとクラスはコンパイル時に定義されるので注意。

クラスが存在するかどうかの判定

<?php
function __autoload($class_name){
  echo $class_name;
}
class A{}
var_dump(class_exists("A"));
var_dump(class_exists("Z"));
var_dump(class_exists("Z", false));

結果

boolean true
Z
boolean false
boolean false

第二引数で__autoload()をコールするかしないかの指定が可能。

関数がコール可能かどうかを判定する

<?php
var_dump(is_callable('A::test'));
class A{
  function test(){}
}

結果

boolean true

クラスと同じく関数定義もコンパイル時に行われるよ

<?php
function __autoload($class_name){
  echo $class_name;
}
var_dump(is_callable('Foo::bar'));
var_dump(is_callable('Foo::protect'));
function hoge()
{
  class Foo
  {
    public function bar(){}
    protected function protect(){}
  }
}
hoge();
var_dump(is_callable('Foo::bar'));
var_dump(is_callable('Foo::protect'));

結果

Foo
boolean false
Foo
boolean false
boolean true
boolean false

method_exists だとコールの可否が判定不能なので is_callable で判定することになる。とうぜん存在しないクラスを使おうとすると __autoload がコールされる

instanceof演算子、is_a()、is_sublcass_of()

<?php
function __autoload($class_name){
  echo $class_name;
}
interface I{}
class _C implements I{}
class C extends _C{}

$c = new C;
$_c = new _C;

var_dump( $c instanceof C );
var_dump( $c instanceof _C );
var_dump( $c instanceof I );
var_dump( $c instanceof X );
var_dump( $c instanceof $_c );

echo "--------------------\n";

var_dump( is_a($c, "C") );
var_dump( is_a($c, "_C") );
var_dump( is_a($c, "I") );
var_dump( is_a($c, "X") );
var_dump( is_a($c, $_c) );

echo "--------------------\n";

var_dump( is_subclass_of($c, "C") );
var_dump( is_subclass_of($c, "_C") );
var_dump( is_subclass_of($c, "I") );
var_dump( is_subclass_of($c, "X") );
var_dump( is_subclass_of($c, $_c) );

結果

boolean true
boolean true
boolean true
boolean false
boolean true
--------------------
boolean true
boolean true
boolean true
boolean false
( ! ) Warning: is_a() expects parameter 2 to be string, object given in *** on line 22
null
--------------------
boolean false
boolean true
boolean true
boolean false
( ! ) Warning: is_subclass_of() expects parameter 2 to be string, object given in *** on line 29
null

php5.1.0以前では instanceof演算子によって__autoload()発動するらしいってばよ

その他いろいろ

まぁマニュアルよんでこんなのもあるんだなーと覚えておくくらいで十分だよね。 あんまり細かい関数まで覚えようとすると時間がすごくかかる… 分からなければ検索すれば済むわけでキチンと覚えるべき部分と 曖昧に覚えておくだけでいい部分を判断できるようにならねば。。

Share
関連記事