The SitePoint Forums have moved.

You can now find them here.
This forum is now closed to new posts, but you can browse existing content.
You can find out more information about the move and how to open a new account (if necessary) here.
If you get stuck you can get support by emailing forums@sitepoint.com

If this is your first visit, be sure to
check out the FAQ by clicking the
link above. You may have to register
before you can post: click the register link above to proceed. To start viewing messages,
select the forum that you want to visit from the selection below.

Could this be a version related issue? They fixed chaining virtuals ($a->b->c, where b and c are virtual) in 5.0.5, and I've no reason to believe your example wouldn't work; I believe I've done it in several occasions.

I tested with 5.1RC.

The key difference between a->b->c and "doubleX" in my example is that get(c) doesn't run on the stack of get(b). At the moment when get(c) is called, get(b) is already completed, hence no "recursion". get(doubleX) invokes get(x), thus attempting to re-enter __get, which is forbidden. I don't think they're going to fix this (http://bugs.php.net/bug.php?id=30002), but who knows...

The problem is (as someone already mentioned) that __get/__set are not reenterable, which IMO makes the whole feature pretty useless. In fact, arrow notation for 'virtual' properties is simply dangerous, because this will fail miserably if gets into __get execution chain.

Ouch, I never saw that coming .... god dammit .... to many bugs for my taste.

And no, it doesn't make the feature useless, because no one cares how the implementation is done as long as the interface just works ...

And let me put it this way. If I have class B that has been used for quite some time, and I need to refactor the code so that I have setters/getters without direct access (whatever the reason), all I care about is to keep the following code working:

PHP Code:

echo $b->x;
echo $b->doubleX;

And by the above method it does ... who cares the implementation is dirty.

It is expected behavior because __get/__set have a simple recursion
protection which disables __get/__set during __get/__set calls.

I really doubt that it's a bug because if we allow calling __get() from
__get() you'll get into endless loop easily, which is of course much
worse than just a notice.

Of course, let's disable recursion all together. No more recursive functions for us we can go in endless loops easily which is of course much worse than just a notice Have I told you guys how much I love PHP ?

I've been rooting around in the internal property access code, I doubt the recursion will be turned off. I have no special knowledge on this, but I get the feeling __get and __set were added to support proxy objects, which they are more than adequate for, rather than to support domain object accessor methods, a task which for which they fall short.

I also hate the "overloading" terminology. Its incredibly confusing. I also don't like when __get and __set are called accessor methods. The terminology I prefer is property not found handler.

The problem is (as someone already mentioned) that __get/__set are not reenterable, which IMO makes the whole feature pretty useless. In fact, arrow notation for 'virtual' properties is simply dangerous, because this will fail miserably if gets into __get execution chain.

Ugh, I'd forgotten about that one. I'll get back to Ruby where sanity pervails...

The real trouble is that "$b->doubleX" _sometimes_ works and _sometimes_ doesn't depending upon from where it's called. You definitely don't want the code that behaves that way.

Actually, it always works outside of the class scope (can't say if it works within the class scope because i've never used it), and that's where virtually all cases of it being used will appear.

Arguing over whether or not __get and __set are an ideal solution, perfectly implemented, or anything else is kind of silly. They work quite well for what they were intended for, and they make many tasks a whole lot simpler (especially when dealing with objects that mostly just store data). If you don't like how they were implemented, either don't use them, or come up with a better solution and submit the patch.

I generally argue that using __set (or set('name',$Val) or setName($Val)) is most often indicative of a class attribute that shouldn't exist in the first place. If you're allowing outside objects to arbitrarily change the value of some object setting (other than perhaps to flip switches or the like) on the fly, you should REALLY think about whether or not you're actually implementing it right in the first place. If you're thinking it'll make it easier to refactor later, you're wrong. Stuff like this will require changing much more than a few accessor calls. All it takes is somebody accidentailly doing (if($Obj->Data = null)) and you've got yourself a guaranteed bug.

__get is extremely useful when you want to implement read-only properties (for preventing coding mistakes, because you can't ever ACTUALLY enforce stuff like this when other people have access to the source).

I don't think that anyone who argues that a class ought to have a well-defined interface should be "kicked in the head" even if they were wrong.

In fact, I'd suggest that the kung fu coders possibly ought to spend some more time at school. Mock objects might make some interesting reading.

No, they should be kicked in the head for creating an equally confusing, untestable, undefined interface that is already implemented in a better way anyway (via __get and __set). If I saw that kind of thing being done by anybody outside of an entry-level programmer, I'd fire them immediately (and, yes, I am in a position to do that sort of thing). If you're going to write bad code, at least don't reinvent the wheel of bad coding practice as well.

Stereo: I'll stand by that forever, just like I would if we were talking about MySQL, Linux, Apache, or any other open-source project. If you don't like what the open-source product offers, and you aren't willing to submit your own code, then maybe you should consider using a proprietary solution. Of course, with properietary software the only answer to the problem is "don't use it". A feature or fix not implemented the way you would like it to be doesn't constitute a bug. A bug is when something doesn't behave the way it was intended to. With open source, you have a solution: implement it the way you'd like it to be implemented. The feature has been extremely useful to a great many people using PHP5, myself included. Could it be better? Probably, but that doesn't mean that:

1.) Changes should be made automatically (decisions about BC, forward compatability, consistency, etc. all have to be taken into account)

2.) It should get high priority (security vulnerabilities are always #1, then major bugs, then new, useful features, and lastly small tweaks and minor bug fixes that benefit a small percentage of users).

Also, if you're going to argue that Zend specifically should take responsibility for it, why not ask the same of Yahoo? Yahoo contributes a whole lot of man power to the PHP project, and is far and away the web company that makes the most extensive use of the software. Their programmers have been responsible for introducing bugs (and fixing them), adding new features (and breaking others), and changing behaviors radically. Arguing that Zend should be held accountable for PHP is like arguing that Novell be held accountable for Linux. There is only one group that can be held accountable for PHP, and that's the PHP developers -- which means a collection of mostly volunteers, sprinkled with a few developers working for companies who benefit by making the project better (and are effectively giving the fruits of their labor to the community at no charge).

The companies I work for (and myself, personally) have never paid Zend one cent, and yet we've made a small fortune off of PHP. What possible justification could we have for holding them accountable for a bug in code that they didn't even write (and, indeed, may not even be aware of?) There are thousands upon thousands of companies out there making their living off of PHP, and if it's anyone's responsibility to make sure that problems get resolved, it's those people and companies.

I've said this numerous times, and I'll repeat it here: If you don't like it, change it, use something else, or just live with it. If you're already using something else, then why are you here in the first place? If you're continually finding that PHP isn't helping you solve problems, then why are you using it?

Anybody using getVar('name') / setVar('name') who's running php5 needs to be kicked in the head.

Using getters / setters on internal properties usually smacks of someone who's spent way too much time in school and not enough actually developing applications that people use.

What kind of nonsense is this? Opinion and hyperbole -- yes. Using getVar('name') / setVar('name') in PHP5 for lots of things, like the Request or Templates, makes perfect sense. If the style you like is to use the __get()/__set() property error handlers -- good for you.

As for the whole "I'm in a position to kick people in the head" thing ... baffling ...

The use of these methods is obvious in java, where you should general keep your variables private. I just don't see the point in PHP.

The point is simple! When you write for instance a class that is publically available you don't want third party users to directly use your instance variables as you might decide you want to change the names of those variables, or you might decide that you need extra calculations/formatting done with a variable when it is passed to the Client of a class.. Using get/set methods you could make these changes and no one would even know nor would they have any problems..

Of course since most projects are for personal (one functional) use only, you wouldn't suffer from this much ... Nevertheless, there is a point to making variables private (Java style) and thus using get/set methods!