$this keyword and compact function

Short answer: don't use compact(). In this situation, it's pointless (in most situations it's pointless, but that's another story). Instead, what's wrong with just returning an array?

return array('variable' => $this->variable);

I know this is old, but I wanted something like this for a project I'm working on. Thought I'd share the solution I came up with:

extract(get_object_vars($this));
return compact('result');

It scales rather nicely. For example:

<?php

class Thing {
    private $x, $y, $z;

    public function __construct($x, $y, $z) {
        $this->x = $x;
        $this->y = $y;
        $this->z = $z;
    }

    public function getXYZ() {
        extract(get_object_vars($this));
        return compact('x', 'y', 'z');
    }
}


$thing = new Thing(1, 2, 3);
print_r($thing->getXYZ());

Use with care.


compact() looks for the variable name in the current symbol table. $this does not exist in there. What do you expect the name of $this to be anyway?

You can do:

class Foo
{
    function __construct()
    {
        $that = $this;
        $var = '2';
        print_r( compact(array('that', 'var')) );
    }
}

Ironically, once you assigned $this to $that, $this can also be compacted with 'this' nistead of 'that'. See http://bugs.php.net/bug.php?id=52110. For performance reasons $this and super-globals are only populated when they are needed. If the aren't needed they don't exist.


EDIT after Update

Your compact($this->result); looks for 'something' defined within the local/current scope of the output() method. Since there is no such variable, the resulting array will be empty. This would work:

public function output() 
{
    $something = 1;
    print_r( compact($this->result) );
}

You'll want to use get_class_vars(), which returns an associative array of all properties (class vars) of the provided class, with the var name as the key. Use get_class_vars( get_called_class() ) from within the class to get that class' name as a string. get_class( $this ) works as well.

Of course, this gives you all the properties of the class (regardless of access control modifier), so chances are you want to also filter this list. An easy (if somewhat obfuscated) way to do this is to use array_intersect_key() along with array_flip() as per this SE Answer. So the whole thing looks like:

array_intersect_key( get_class_vars( get_called_class() ), array_flip( array( 'var_1', 'var_2', 'var_3' ) ) );

You'll have to decide if the resulting code is really worth it. It's probably easier to read array( 'var_1' => $this->var_1, 'var_2' => $this->var_2 ); as @ircmaxell points out.

However, because a) I like Yak Shaving and b) because I am a very industrious lazy programmer and c) there was probably a one-liner in Perl that did this elegantly, here's the code in the context of the problem I was trying to address: overriding an associative array (that's also a property of the current class) with a number (but not all) of other properties of the same class.

<?php
class Test {
    protected $var_1 = 'foo';
    private $var_2 = 'bar';
    public $var_3 = 'baz';
    private $ignored_var = 'meh';

    public $ary = array( 
        'var_1' => 'bletch',
        'var_2' => 'belch',
        'var_4' => 'gumbo',
        'var_5' => 'thumbo'
    );

    public function test(){
        $override = array_intersect_key( get_class_vars( get_called_class() ), array_flip( array( 'var_1', 'var_2', 'var_3' ) ) );
        return array_merge( $this->ary, $override );
    }
}

$test = new Test();
var_dump( $test->test() );

Which produces the expected output:

array(5) { ["var_1"]=> string(3) "foo" ["var_2"]=> string(3) "bar" ["var_4"]=> string(5) "gumbo" ["var_5"]=> string(6) "thumbo" ["var_3"]=> string(3) "baz" }

Note that in my own usage, I wouldn't have broken this out into 2 lines, but I wanted to keep the code that refers to the OP separate.

Tags:

Php

Oop

Arrays