4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

get_object_varsでprivate/protectedなプロパティを取りたい

Last updated at Posted at 2013-07-08

 get_object_varsはオブジェクトのプロパティを連想配列で取得できる便利な関数ですが、残念なことに現在のスコープでアクセスできるプロパティしか取得できません。ですのでテストやデバッグ時には使えません。

そこで、リフレクションを使って無理矢理にprivate/protectedなプロパティへアクセスする関数を作ってみます。


テストプログラム
<?php
class GrandParentClass
{
	public    $grandparent_public_var = 1;
	protected $grandparent_protected_var = 2;
	private   $grandparent_private_var = 3;

	public    $public_var = 10;
	protected $protected_var = 11;
	private   $private_var = 12;

	public function getObjectVars()
	{
		return get_object_vars($this);
	}
}
class ParentClass extends GrandParentClass
{
	public    $parent_public_var = 4;
	protected $parent_protected_var = 5;
	private   $parent_private_var = 6;

	public    $public_var = 13;
	protected $protected_var = 14;
	private   $private_var = 15;

	public function getObjectVars()
	{
		return array_merge(parent::getObjectVars(), get_object_vars($this) );
	}
}
class ChildClass extends ParentClass
{
	public    $child_public_var = 7;
	protected $child_protected_var = 8;
	private   $child_private_var = 9;

	public    $public_var = 16;
	protected $protected_var = 17;
	private   $private_var = 18;

	public function getObjectVars()
	{
		return array_merge(parent::getObjectVars(), get_object_vars($this) );
	}
}

function get_object_vars_ex( $obj )
{
	$ref = new ReflectionObject( $obj );
	$vars = get_object_vars_me_and_parent( $obj, $ref );
	return $vars;
}

function get_object_vars_me_and_parent( $obj, $ref )
{
	$vars = array();

	$props = $ref->getProperties();
	foreach( $props as $p ){
		$p->setAccessible(true);

		$vars[$p->getName()] = $p->getValue($obj);
	}

	$parent = $ref->getParentClass();
	if ( $parent !== FALSE ){
		$vars_parent = get_object_vars_me_and_parent( $obj, $parent );
		$vars = array_merge( $vars_parent, $vars );
	}

	return $vars;
}

$me = new ChildClass();

// TEST1: get_object_vars
$start = microtime(true);
$result1 = get_object_vars($me);
$elapse1 = round((microtime(true) - $start) * 1000,10);

// TEST2: array cast
$start = microtime(true);
$result2 = (array)($me);
$elapse2 = round((microtime(true) - $start) * 1000,10);

// TEST3: getObjectVars
$start = microtime(true);
$result3 = $me->getObjectVars();
$elapse3 = round((microtime(true) - $start) * 1000,10);

// TEST4: get_object_vars_ex
$start = microtime(true);
$result4 = get_object_vars_ex($me);
$elapse4 = round((microtime(true) - $start) * 1000,10);

echo "------- result -------" . PHP_EOL;
echo "result1:" . print_r($result1,true) . PHP_EOL;
echo "result2:" . print_r($result2,true) . PHP_EOL;
echo "result3:" . print_r($result3,true) . PHP_EOL;
echo "result4:" . print_r($result4,true) . PHP_EOL;

echo "------- time -------" . PHP_EOL;
echo "elapse1: {$elapse1}" . PHP_EOL;
echo "elapse2: {$elapse2}" . PHP_EOL;
echo "elapse3: {$elapse3}" . PHP_EOL;
echo "elapse4: {$elapse4}" . PHP_EOL;
実行結果
------- result -------
result1:Array
(
    [child_public_var] => 7
    [public_var] => 16
    [parent_public_var] => 4
    [grandparent_public_var] => 1
)

result2:Array
(
    [child_public_var] => 7
    [ * child_protected_var] => 8
    [ ChildClass child_private_var] => 9
    [public_var] => 16
    [ * protected_var] => 17
    [ ChildClass private_var] => 18
    [parent_public_var] => 4
    [ * parent_protected_var] => 5
    [ ParentClass parent_private_var] => 6
    [ ParentClass private_var] => 15
    [grandparent_public_var] => 1
    [ * grandparent_protected_var] => 2
    [ GrandParentClass grandparent_private_var] => 3
    [ GrandParentClass private_var] => 12
)

result3:Array
(
    [child_public_var] => 7
    [child_protected_var] => 8
    [public_var] => 16
    [protected_var] => 17
    [parent_public_var] => 4
    [parent_protected_var] => 5
    [grandparent_public_var] => 1
    [grandparent_protected_var] => 2
    [grandparent_private_var] => 3
    [private_var] => 18
    [parent_private_var] => 6
    [child_private_var] => 9
)

result4:Array
(
    [grandparent_public_var] => 1
    [grandparent_protected_var] => 2
    [grandparent_private_var] => 3
    [public_var] => 16
    [protected_var] => 17
    [private_var] => 18
    [parent_public_var] => 4
    [parent_protected_var] => 5
    [parent_private_var] => 6
    [child_public_var] => 7
    [child_protected_var] => 8
    [child_private_var] => 9
)

------- time -------
elapse1: 0.0231266022
elapse2: 0.0140666962
elapse3: 0.0741481781
elapse4: 0.3459453583


 リフレクションでプロパティにアクセスする際、リフレクションオブジェクトのgetProperties()メソッドを呼び出して各プロパティのオブジェクトを取得できるのですが、その際にsetAccessible(true)をしてあげないとReflectionExceptionが発生します。

 Arrayへのキャストでもprivate/protectedプロパティは取得できますが、値のキー名がおかしなことになっています。内部でget_object_varsを呼び出しているTEST3は要件を満たしていますが、テスト対象のクラスにメソッドを実装することになるのでテストには不向きでしょう。

 今回作成したリフレクションバージョンのget_object_vars関数(get_object_vars_ex)は要件を満たしていますが、ベンチマークを取るとTEST3の5倍も遅いという結果に。うーん。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?