leedavis81/altr-ego

访问对象受保护/私有属性和方法

v1.0.2 2013-07-25 17:43 UTC

This package is not auto-updated.

Last update: 2024-09-23 11:32:44 UTC


README

Build Status Total Downloads Latest Stable Version

一个工具,允许您通过破坏PHP作用域来访问对象的受保护/私有属性。这在测试场景中非常有用,您想快速验证应用程序中隐藏的封装过程。通常,当您只想测试应用程序的某个小部分时,该过程可以(正确地)封装并设置为私有/保护。并且无法从您的测试套件中调用。运行创建、模拟和注入依赖以使对象处于测试有效状态的流程可能非常耗时。这个工具可以帮助您直接调用该私有过程或检查该受保护属性。

AltrEgo允许您在任意操作过程中完全保持对象的状态。如果您决定希望作用域重新生效,您只需重新获取对象。在其作为“AltrEgo”对象的时间期间所做的任何更改都将保持不变。

此库使用适配器来适配不同版本的PHP。

如果您正在使用5.3

那么将使用PHP的Reflection类来破坏您对象的作用域。

对于5.4,此库使用闭包作用域绑定

PHP 5.4使用闭包提供了新的“作用域破坏”功能。请参阅Davey Shafik的闭包谜题博客文章,以了解此功能的工作原理。此方法比使用PHP的内置反射工具快得多。我进行的“破坏作用域”测试表明,速度提高了大约52%。

用法

// Given the following class (nice and private all round)
class Foo
{
    private $priv = 'This is a private variable';

    private $privArray = array('private array entry');

    private function privFunc($value)
    {
        return $value;
    }

    private static function privStatFunc($value)
    {
        return $value;
    }
}

// We first off create an alter ego
$alterEgo = AltrEgo::create(new Foo());

// Right, now lets get a hook on those private bits
echo $alterEgo->priv . PHP_EOL;
// Output: This is a private variable

// Woot, works, now lets set it to something else and see what happens
$alterEgo->priv = 'new private value';
echo $alterEgo->priv . PHP_EOL;
// Output: new private value

// This value remains on your object, even after retrieving it back with $alterEgo->getObject()
// now lets try some method calls
echo $alterEgo->privFunc('Private call') . PHP_EOL;
//Output: Private call

// Now then, onto arrays; You can pass in an array of parameters like so:
var_dump($alterEgo->privFunc('Private', 'call'));
/**
Output: 
array(2) {
  [0]=>
  string(7) "Private"
  [1]=>
  string(4) "call"
}
*/

// You can push values straight into them using standard PHP array syntax. 
// But be aware, the array will be converted (and maintained) as an ArrayObject
$alterEgo->privArray[] = 'new value';
var_dump($alterEgo->privArray);
/**
Output: 
object(ArrayObject)#5 (1) {
  ["storage":"ArrayObject":private]=>
  array(2) {
    [0]=>
    string(19) "private array entry"
    [1]=>
    string(9) "new value"
  }
}
*/

// You can add associative array values and unset them as you normally would in PHP
$alterEgo->privArray['assoc_key'] = 'private key value entry';
var_dump($alterEgo->privArray);
unset($alterEgo->privArray['assoc_key']);
var_dump($alterEgo->privArray);
/**
Output: 
object(ArrayObject)#5 (1) {
  ["storage":"ArrayObject":private]=>
  array(3) {
    [0]=>
    string(19) "private array entry"
    [1]=>
    string(9) "new value"
    ["assoc_key"]=>
    string(23) "private key value entry"
  }
}
object(ArrayObject)#5 (1) {
  ["storage":"ArrayObject":private]=>
  array(2) {
    [0]=>
    string(19) "private array entry"
    [1]=>
    string(9) "new value"
  }
}
*/

// We also have the facility to execute static function that have private/protected visibility.
// It's rare you'll ever come across these, they're typically set as public so you'd normally call them directly
echo AltrEgo::callStatic($alterEgo, 'privStatFunc', 'private static call') . PHP_EOL;
// Output: private static call

// Also works with arrays
var_dump(AltrEgo::callStatic($alterEgo, 'privStatFunc', array('private', 'static', 'call'))); 
/**
Output: 
array(3) {
  [0]=>
  string(7) "private"
  [1]=>
  string(6) "static"
  [2]=>
  string(4) "call"
}
*/

// If at anytime you want to jump back into scope just fetch your object back.
// You can throw it back into AltrEgo::create() whenever you need
$backToScope = $alterEgo->getObject();

局限性

  1. 在访问数组属性时,它将被转换为(并维护)ArrayObject。这是由于使用PHP重载(__get)设置数组值时的限制。如果您遇到问题,可以直接获取值,然后用修改后的值覆盖它。或者一旦您检索到修改后的ArrayObject,只需对其运行 ->toArray()。