5

I'm trying to dump elements of an object's private property through an anonymous function - of course I could achieve this in any number of other ways, but this highlights a PHP conundrum I can't solve off the top of my head, short of $foo = $this and using $foo - but THAT won't give me the private stuff, so... suggestions ?

Sample code:

class MyClass
{
    private $payload = Array( 'a' => 'A element', 'b' => 'B element');

    static $csvOrder = Array('b','a');

    public function toCSV(){
        $values = array_map(
            function($name) use ($this) { return $this->payload[$name]; },  
            self::$csvOrder
        );
        return implode(',',$values);
    }
}

$mc = new MyClass();
print $mc->toCSV();
NikiC
  • 100,734
  • 37
  • 191
  • 225
Wagemage
  • 300
  • 1
  • 4
  • 10
  • 1
    Dup of ["Accessing private variables from within a closure"](http://stackoverflow.com/q/3722394/90527), but NikiC's answer works for accessing non-public methods as well as non-public properties, so not voting for closure. – outis Feb 13 '12 at 12:24

3 Answers3

3

I believe there is absolutely no way to do directly what you propose.

However, you can work around it either by making the anonymous method a class method (this is not what you asked for, but it could be a practical solution) or pulling everything you need out of $this explicitly and passing the extracted values into the function:

class MyClass
{
    private $payload = Array( 'a' => 'A element', 'b' => 'B element');

    static $csvOrder = Array('b','a');

    public function toCSV(){
        $payload = $this->payload;
        $values = array_map(
            function($name) use ($payload) { return $payload[$name]; },  
            self::$csvOrder
        );
        return implode(',',$values);
    }
}
Jon
  • 428,835
  • 81
  • 738
  • 806
  • Indeed - your code reflects what I ended up doing in this particular case. Oh well, it's an interesting problem in general - was hoping there was a way to address the issue I was simply unaware of. Thanks for the answer :) – Wagemage Jun 17 '11 at 14:02
  • +1 I posted an answer with this before I realized that you already said it. The simplest solution is often the best. – Andrew Curioso Jun 17 '11 at 14:10
3

You can hack around the limitation by creating a wrapper that utilizes Reflection to allow you to access all properties and methods. You can use it like this then:

$self = new FullAccessWrapper($this);
function () use ($self) { /* ... */ }

Here a sample implementation of the wrapper, taken from here:

class FullAccessWrapper
{
    protected $_self;
    protected $_refl;

    public function __construct($self)
    {
        $this->_self = $self;
        $this->_refl = new ReflectionObject($self);
    }

    public function __call($method, $args)
    {
        $mrefl = $this->_refl->getMethod($method);
        $mrefl->setAccessible(true);
        return $mrefl->invokeArgs($this->_self, $args);
    }

    public function __set($name, $value)
    {
        $prefl = $this->_refl->getProperty($name);
        $prefl->setAccessible(true);
        $prefl->setValue($this->_self, $value);
    }

    public function __get($name)
    {
        $prefl = $this->_refl->getProperty($name);
        $prefl->setAccessible(true);
        return $prefl->getValue($this->_self);
    }

    public function __isset($name)
    {
        $value = $this->__get($name);
        return isset($value);
    }
}

Obviously the above implementation doesn't cover all aspects (e.g. it can't use magic properties and methods).

NikiC
  • 100,734
  • 37
  • 191
  • 225
  • Interestingly evil :) Of course probably not what I'd do for production, but it *does* solve the problem - thanks – Wagemage Jun 17 '11 at 14:05
1

As you said yourself, it is private and therefore in accessible.

You can:

  • Pass $this->payload as a parameter to the anonymous function.
  • Create a method in the class and use it instead.
Shay Ben Moshe
  • 1,298
  • 3
  • 12
  • 27