views:

266

answers:

4

Why does PHP require you to explicitly write $this? I would understand if you had to use $this here:

function foo($bar) {
   $this->bar = $bar;
}

But you must write it explicitly in verbose code that looks like this:

$this->var3 = globalFun($this->var, $this->var2[$this->anotherVar], $this->method());

as opposed to:

$var3 = globaFun($var, $var2[$anotherVar], method());

So what is the point of $this?

Additional Bonus Question:

Why do we have to differentiate static references and instances? Why do we need:

static function getValue() {
   return self::value;
}

Can't PHP find out at runtime if the variable/method in question is static? Now if I want to change a method from static to non-static, I have to replace all those self:: with $this-> (and vice-versa).

Wouldn't it be better if we had a $this that behaves like it does in Java?

+1  A: 

Actually, I know people who use this. in Java even where unnecessary because they feel it creates clearer code ;) I don't have a really definite answer, but I guess that, internally, getting $var would always have to be translated to $this->var. So it's not like someone intentionally made things more complicated by forcing us to do $this->var, but just decided to not implement the $var shortcut. If that helps in any way, I don't know ;)

Nicolas78
a similar argument may be made for the self:: - it's not the same thing, it doesn't lie in the same space, and it doesn't really make the code nicer to conceil the difference
Nicolas78
i've seen code that uses 'this' and 'm_' throughou. overkill if you ask me
Gabriel
+6  A: 

PHP was not OOP.

Now it is, but with side effects.

Guillaume Lebourgeois
+7  A: 

Okay, so let's remove the need for writing $this everywhere. Take a look at this situation:

class Foo {
    public function setBar($value) {
        $bar = $value;
    }
}
$foo = new Foo();
$foo->setBar('some value');

Is $bar a local variable or a member of $foo?

There has to be some differentiation. They could have allowed declaration of local variables with the var keyword, but that would not have been backwards-compatible and would have been very confusing to people upgrading from older versions of PHP.

Same thing applies to self::. How does the interpreter know whether the function you wanted to call is global or specific to the class?

musicfreak
`$bar` is a local variable, in `setBar()`'s scope, since Foo doesn't have a member called `$bar`.
NullUserException
@NullUserException: But now you just removed a feature from PHP: being able to dynamically add members to an object.
musicfreak
@NullUserException: Because the two actions are semantically different. When you use `$this`, you are referring to *an instance* of a class. When you are using `self::`, you are referring to *the class itself*. Obviously the developers of PHP thought this difference was important enough to warrant having a separate syntax for each.
musicfreak
@musicfreak: One could still explicitly type `$this->` even if it weren't mandatory, thus no feature would have been removed.
konforce
@konforce: True, but that would become confusing and error-prone. Also, it doesn't really help with functions and `self::`. (How do you call a global function with the same name as a method?)
musicfreak
The same way you do in other languages: use the empty scope operator to disambiguate as needed. (e.g., `::foo()` always calls a global function). Also, using namespaces and classes can avoid the problem altogether.
konforce
@konforce: Right, but my point is that you still need special syntax for one case or the other. There's also compatibility to consider. The developers of PHP obviously regard backwards compatibility higher than how "pretty" or readable the language is (which in my opinion is a bad decision, but that's another debate).
musicfreak
+10  A: 

Since this was re-opened, I'll post here my answer, as promised.

TL;DR version If it were not required to qualify a member access, there would be not only performance penalties, but the same line of code could simultaneously signify a field access and a local variable access, depending on the code path.

Full version

In PHP, there's always one symbol table active at the table. This is either the global symbol table or a function/method local symbol table (which by the way, are lazily built). Superglobals and optimizations like compiled variables aside, when a variable $var is requested, it is looked up in the current symbol table. Since the object properties live not on the symbol tables, but instead on either in the objects (the instance properties) or the structure associated the class (the static properties), a lookup for $var can never return a property.

To bring a given variable to the function scope, you must explicitly signal your intention by creating a reference. Examples:

$myglobal = 7;
class A {
    private $prop;
    public function meth() {
        global $myglobal; //bring a global to the current scope
        $prop =& $this->prop; //brings a property to the current scope
        $local = 4;
        $lambda = function () use (&$local) { };
    }
}

Obviously, this is just a more sophisticated way to phrase what currently happens. The question is why this behavior?

After all, in Java we only have to type this.prop when there's a local variable called prop hiding the property. Why is this not a good option for PHP?

I can think of several reasons.

The object properties are determined at runtime

PHP has something called "dynamic properties". You can assign new properties to objects at runtime. In fact given two objects of the same class, one can have a given property $a and while the other doesn't. Example:

$obj1 = new stdClass();
$obj2 = new stdClass();
$obj1->a = 7;

In PHP, the defined local variables are determined at runtime

Variables do not have to be declared; consequently, depending on the code path, at some point a variable may or may not be defined. To add insult to the injury, we also have the monster called "variable variables". Example:

class A {
    private $g = 3;
    public function func($varname) {
        if (rand(1,2) == 1) {
            $g = 4; //no block scope; the scope is the function's
        }
        $$varname = 5; //god knows what's happening here
        //if local variables hid properties, we'd have trouble
    }
}

In Java, a given identifier may also represent, inside the same function, a local variable and a property, but:

  • Not within the same block (in PHP, all blocks in a function share exactly the same scope).
  • You get a warning if you're hiding a property.
  • Crucially, in any given occurrence of an identifier, it's either a property or a local variable, it can't sometimes be one and other times the other.

Consequences

Owing to these facts, it would be impossible to determine at compile time if $var referred to a local variable or to a property. Consequently:

  • At runtime, every time a variable occurred, it would have to looked up first in the local symbol table, then in the instance properties table, and finally in the static properties list, or any other order (since there can't be an instance and a static property with the same name and static properties need to be declared, there would be some optimization potential here, but the point stands). This means a symbol would have, in the worst case, would have to be looked up in three different places. This is bad from a performance perspective.
  • A given symbol occurrence could mean different things on different occasions. This is a recipe for disaster.
Artefacto