Why does this work? Why does this show the email address?
#1
<?php
class person {
private $email = “foo”;
function showEmail() {
echo $this->email;
}
}
class user extends person {}
$u = new user();
$u->showEmail();
but this doesn’t?
#2
<?php
class person {
private $email = “foo”;
}
class user extends person {
function showEmail() {
echo $this->email;
}
}
$u = new user();
$u->showEmail();
Also, why does this work
#3
<?php
class person {
private $email = “foo”;
function showEmail() {
echo $this->email;
}}
class user extends person {
function showEmail() {
parent::showEmail();
}
}
$u = new user();
$u->showEmail();
Actually, #2 is one that makes sense to me and I can explain. The $email is private in the parent class, and is not visible in the child class. With E_ALL on, I’d get a notice about ‘undefined property’.
The concept of $this in PHP seems, to the outside eye, to be capricious at best and somewhat broken at worst. As someone who has to field questions on this sort of stuff, from developers with OO experience in other languages, trying to explain it (not even defend it, just explain it) is often difficult.

#3 can arguably make sense too, if you think that the $this in the ‘person’ class should really be evaluated in the person context, not the ‘user’ context in which $this would normally apply (specifically, it would evaluate as ‘person’ context because we’ve explicitly called parent::).
Seems like the private attributes of the parent class does not exists on the child class, but only in the parent scope. You can redeclare $email in the child class , this will give your class two $email attributes, one will be used when called from child scope other from parent. That’s odd.
Protected will work as it should, with User been able to echo $email.
#2
If you set
protected $email = “foo”;
it would be accessible in the child class
1) your $email property is private, so the subclass doesn’t have access to it.
Hi!
The scope “private” means that a property is only accessible in the class itself, not in derived or parent classes.
In #1 the showEmail() method is declared in the class the private property $email belongs too. In the derived class, you call the method which is actually implemented in the base class and therefore may access the private properties defined in this class, too.
In #2 you try to access the private property of the parent class, which is not allowed since it is declared “private”.
In #3 you do not access the “private” property of the parent class, but the “public” method of it. Since this method is declared on the parent class, it is also allowed to access its private properties.
So, nothing wrong here, just OOP.
Cheers,
Toby
So your question is:
Why does PHP behave exactly like the manual tells me it should?
Is that what your question is?
To my students, I often teach private/protected and getters/setters by using the metaphor of a bank vault and a bank teller. You can’t just walk into the vault and get your money. You have to see a teller first. The teller may want to check your credentials, check your account balance, or do some logging of the event, before finally giving you money. (Setters, aka “deposits” work the same way in reverse.)
To stretch that metaphor a bit to fit your question:
In #2, your bank teller is from a different bank and doesn’t even know about the vault, much less have access.
#3 is like driving up to the public window to see the teller. Same teller, available to the public anytime. IMO, it illustrates why it’s always a good idea to declare methods as “public function” instead of just “function” to remind yourself that it’s public by default.
In #1, you are inheriting the bank teller. Even though you didn’t inherit the vault too, the teller is one and the same and DOES know all about the vault and still has access. (Maybe you could think of it as having a bank teller on site at your company who can make trips back to the bank vault when needed.)
Hope that helps.
This behavior is consistent with other OOP languages like Java and C++…
That’s the difference between protected and private.
I guess what I’m getting at is the difference between this
email;
}
}
class u extends p {}
$u = new u();
$u->showEmail();
// echoes ‘mike’
and this
email;
}
}
$u = new u();
$u->showEmail();
// notice – undefined property
Doesn’t seem to me that the behaviour should change based on *where* the showEmail() method is defined, but that seems to be what’s happening.
Hehe – OK – half that comment was cut off, but basically, the visibility and access is impacted as to where the method being called is defined itself. Put another way, “the calling context is not the class of the object, but the class in which the method was defined”. Accurate?
I agree with Toby – all of this is expected behaviour.
Not sure I entirely agree it’s all ‘expected’, or at the very least the docs could use some updating with a clearer explanation of what’s meant.
< ?php
error_reporting(E_ALL);
class p {
private $email = "privateEmail";
public $name = "dave";
protected function showEmail() {
echo "In p class, \$this is a ".get_class($this)." class\n";
echo "email=".$this->email.”\n”;
echo “name=”.$this->name.”\n”;
}
}
class u extends p {
private $email = “privateEmail2″;
public $name = “mike”;
function showEmail() {
echo parent::showEmail().”\n”;
echo “In u class, \$this is a “.get_class($this).” class\n”;
echo “email=”.$this->email.”\n”;
echo “name=”.$this->name.”\n”;
}
}
$u = new u();
$u->showEmail();
In this example, we’d get
In P class, $this is a u class
email=privateEmail
name=mike
In U class, $this is a u class
email=privateEmail2
name=mike
So, the ‘private’ is specific (seemingly static?) to the class definition, regardless of what $this really is. Whether this is ‘expected’ or ‘works like this in Java and C++’ or whatever, it’s still rather confusing. $this takes on different meanings based on where it’s executing. At least, that’s what it appears to do – someone will undoubtedly come and school me by telling me how dumb I am, or how awesome PPP in PHP is, or something else equally comforting.
i think you just discovered the difference between ‘private’ and ‘protected’
I recently had some confusion like this, but more to do with protected. I can’t understand why the visibility is based on class, rather than instance of a class.
I wrote about it here http://www.davedevelopment.co.uk/2009/02/25/how-protected-is-protected/
I see what you’re asking, and it is interesting behaviour when you really think about it. Too bad that several commenters missed the point yet still felt the need to weigh in with patronising remarks.
Interesting Dave, that you said it was a ‘bug’ in the 5.1 series. Did it work differently before that? It’s somewhat amusing to me that the docs can say XXX, give examples, things work a certain way, then in the next version it’s different, and the previous way (which people built on) is labelled ‘a bug’. Where is the documentation as to how all this stuff was intended to work from the outset, so we can determine what’s a ‘bug’ in the first place? How would anyone write tests for this? What’s a ‘bug’ seems to be very subjective.
@Kevin:
Ham-handed analogies will do nothing to make getters and setters any less redundant.
I agree that this is expected behaviour. If a parent class defines a property as private you can only access it if the parrent allows you to by defining a public method. A child cannot define it’s own public method to access parent’s private properties. It’s like asking your father to let you borrow a car. You can’t just take it without asking.
This is a very basic OOP principle that I would expect someone who has OOP listed in their resume to know. Most OOP books or PHP certification classes will cover this topic in more detail.
@simon – I’m used to the patronizing remarks. I get it all the time.
Tried some of these in Java and I saw at least one discrepancy, but that’s possibly to be expected because I’m using “super.showEmail()” instead of “parent::showEmail()”. There’s likely a subtlety between super and parent going on, but I don’t seem to find much on the PHP docs about how parent is expected to work. I see how it’s *working* (for now) but I don’t know if this is how it’s really intended to work, or if we’ll see something change in PHP6. Given the scant documentation (that I see) about expected and defined behaviour for parent, there may easily be a change that might go unnoticed for a spell… :/ Surely if I’m wrong on the doc part someone will yet again call me out publicly and point me to docs that describe the specific intended behaviour.
The point of confusion to me now seems to be the scoping – given that in a parent class “$this” is still the “child” class (when called via parent::) but has access to the parent’s private properties. The child class normally wouldn’t have access to the parent’s private properties, but if somehow the method being executed is the one defined in the parent scope (and not an overridden one) the private variables get exposed. Note that any overridden public properties (and possibly protected – I haven’t tried that ) will still be shown from the child class instance, even though we’re operating in the parent context and have access to the parent’s private variables. THAT is still confusing, and likely always will be.
@Herman – This whole thing started when going over some PPP stuff in a class that I teach. If you reread the initial post, I was simply asking ‘why’ something worked. I didn’t say I didn’t know mechanically if it was right or wrong, but was looking for explanations. Possibly I wasn’t that clear, but to just get a bunch of people coming in and telling me I’m stupid is a bit offputting, to say the least.
Whether or not I *know* it, it’s still confusing, and it’s confusing to teach. I *am* PHP certified, and am teaching. I’ve also bounced it off some other colleagues (one of whom is also a certified teacher, and another who’s been a Java developer for years who is now doing PHP) and they’re not able to come up with easily understood explanations suitable for those new to the subject either. In fact, the Java colleague accurately predicted how the behaviour would work in a Java env (using the super) but was a bit surprised that parent:: didn’t work quite the same way.
The basics of PPP – sure. X inherits from Y, etc. But when you start dealing with what might arguably called an edge case above, it’s harder to come up with a short, understandable explanation to accurately express what’s going on and why.
I am probably beating a dead horse but access specifiers are observed at the class level, not the instance level. There are many good reasons for this.
If access was observed at the instance level it would make polymorphism much less useful. You would have to know much more precisely how your code is going to be used and extended in the future. If visibility was instance based and worked in such a way that if ‘$this’ was a subclass you couldn’t access parent private properties even if the code the method was in is inside of the parent class then that single method is going to behave differently whenever you extend the class as soon as it accesses a private property or method the first time.
You could never call a parent method and be sure that it would actually work without reviewing the code in that parent method to make sure it didn’t call any private methods or access any private properties. While this isn’t necessarily difficult with a language like php, it is still a large hassle. Also, imagine how hard it would be to work with compiled languages and shared libraries if this were the case.
There would also be a measurable slow down in compiled languages if visibility was instance based as you would have to determine the validity of method calls at runtime instead of compile time. This means using things like RTTI in C++ and Java.
I suppose one could still argue the validity of this behavior. However, there are very, very good reasons that visibility is interpreted at the class level.
This was a conclusion reached after spending some time working through some of this with a colleague by phone. I’d meant to reference this a bit in the earlier reply, but got a bit more focused on the semantics and motivation of the original post.
Thank you for the explanation. It’s about as clear as any I’ve heard about the ‘why’ one approach over another.
Hi Michael,
If you don’t mind a bit of advice, I think you could have easily changed the tone of the comments by rewording your final paragraph. Asking questions in your blog is generally good and can often lead to good answers. When this is the case, the result is a page that is useful to those who may follow. Toby, Mike, and a few others seem to realize this and try to provide helpful answers despite your tone, but it’s pretty easy to see why others do not.
To use my own reaction to help explain what I mean, I read through your post thinking to myself, “how could I explain this better, so that it makes as much sense to Michael as it does to me?” I do think the behavior is pretty obvious. In fact, these examples just demonstrate the point of visibility. They don’t seem like edge cases to me at all.
Knowing that this behavior is very simple and clear to most developers, consider your final paragraph again:
“The concept of $this in PHP seems, to the outside eye, to be capricious at best and somewhat broken at worst. As someone who has to field questions on this sort of stuff, from developers with OO experience in other languages, trying to explain it (not even defend it, just explain it) is often difficult.”
Can you guess what affect this had on my reaction? I suddenly felt like I had wasted my time reading this, and without scrolling down, I knew most of the comments would be disparaging.
Maybe this still seems like the most appropriate tone to you, but I hope you can see how it seems like you’re taking no responsibility: the confusion is others’, not yours; you know how this works; you’re just the helpful messenger letting everyone know that PHP’s behavior seems broken.
The slightest hint of arrogance, especially when you’re revealing such a lack of experience, can cause some harsh reactions. To be honest, I’m surprised you weren’t skewered. If your post had a humble tone to it, and you seemed to be genuinely asking for a simple explanation of visibility that would be appropriate for beginners, I bet almost every response would have been helpful.
I hope this is helpful. If not, feel free to delete it.
The skewering (to the extent that it was done) probably was a reaction to the capricious comment more than anything else. I was not in a very good mood when I wrote this – waiting a day may have helped tone it down some. Having said that, the reactions from many others here was no better – arguably worse (as in insulting specifically to me). Nothing in the original comment indicated the confusion was in others – I was specifically calling out myself as not ‘getting’ how to explain why the original examples worked.
Certainly some of the original post was not intended as ‘I know how it works and this is broken’, but rather how it appears. I guess that’s a distinction that wasn’t drawn out enough in the original post. I’ve gone to the php.net docs looking for more info on how parent:: and $this-> visibility is to behave, and did not see anything which specifically addressed my question.
Thank you for the post nonetheless Chris, as you’re describing something which will likely help future posts/questions.
Ah, but remember PHP is a volunteer project – if you would like a page on “how parent:: and $this-> visibility is to behave” feel free to file a documentation bug. If you know enough to write some text – Phillip would love to have it for the manual
Moral of the story – less whining, more coding
I’m 100% *NOT* the person to be writing this up – precisely because I don’t understand how it works, and apparently I just don’t understand OOP at all (see 90% of the comments above). Yes, it’s volunteer project, but it might still be nice to have some guidelines for volunteers to follow, as in – at least jot down some notes when you’re writing something so others can refer to them when looking to write documentation. All one could do now is look at the underlying C code as to *how* it works right now, not how it was intended to work.
Not every criticism is ‘whining’. Also, when basic doc stuff has been reported broken, and filed bug reports against, not fixed after years, or things get marked ‘bogus’ (a slightly patronizing tone to the word) one tends to lose a bit of faith in the process. (bug 47751, 36461, 29534.
Heh, I’m now frightened to death of PHP