PHP programmers don't really understand PHP.
They know how to use PHP - but they hardly know how it works, mainly because it Just Works most of the time. But such wilful ignorance (otherwise known as abstraction) often runs them aground on some issues when their code meets the stupidity that is APC. Bear with me while I explain how something very simple about PHP - how includes work.
Every single include that you do in PHP is evaluated at runtime. This is necessary so that you could technically write an include inside an if condition or a while loop and have it behave as you would expect. But executing PHP in Zend is actually a two step process - compile *and* execute, of which APC gets to handle only the first.
Compilation: Compiling a php file gives a single opcode stream, a list of functions & yet another list of classes. The includes in that file are only processed when you actually execute the code compiled. To simplify things a bit, take a look at how the following code would be executed.
<?php return; include_once "a.php"; ?>
The PHP compiler does generate an instruction to include file "a.php", but since the engine never executed it, no error is thrown for the absence of a.php. Having understood how includes work, classes & OOP face a unique problem during compilation.
<?php include_once "parent.php"; class Child extends Parent { } ?>
Even though the class Child is created at compile time, its parent class is not available in the class table until the include instruction is actually executed & the parent.php compiled up. So, php generates a runtime class declaration which is an actual pair of opcodes.
ZEND_FETCH_CLASS :1, 'Parent' ZEND_DECLARE_INHERITED_CLASS null, '<mangled>', 'child
But what if the class parent was already in the class table when the file was being compiled? Like the following index.php
include_once "parent.php"; include_once "child.php"; $a = new Child();
Since obviously the parent class is already compiled & ready, Zend does something intelligent by removing the two instructions and replacing them by NOPs. That makes for fewer opcodes and therefore faster execution.
Here's the kicker of the problem. Which of these versions should APC cache? Obviously, the dynamically inherited version is valid for both cases - but APC caches whatever it encounters initially. The static version is obviously incompatible in a dynamic scenario.
So whenever APC detects that it has cached a static version, but this case actually requires a dynamic version, it decides to not cache that file *at* all from that point onwards. That's what the APC autofiltering does.
Now, you ask - how could it appear in perfectly normal code?
Assume child1 and child2 inherits from parent class. And here is how the first hit on index.php looks like from an inclusion perspective. Now, it is obvious that the child2 in this case is actually compiled with the faster static inheritance (marked in orange) while child1 suffers the performance hit of not having Parent available till execution time.
Then we have a profile.php which only requires the child2 class. But while executing this file, APC fetches the copy of child2.php which was in cache - which is the statically inherited one.
As you could've guessed, the cached version is not usuable for this case - and APC drops it out of cache. And for all requests henceforth, even for the index.php case, APC actually ignores the cached version and insists on compiling the file with Zend. If you enable apc.report_autofilter, this information will be printed out into the server error log.
Part of the culprit here is the conditional inclusion using include_once. With mere includes, you get an error whenever parent.php is included multiple times - but that can be annoying too. Where include_once/require_once can be debugged with Inclued, userspace hacks like the rinclude_once or !class_exists() checks make it really hard for me to figure out what's going wrong.
So, if you write One File per Class PHP and use such methods of inclusion, be prepared to sacrifice a certain amount of performance by doing so.
--Doubt is not a pleasant condition, but certainty is absurd.
-- Voltaire
I'm officially starting to refer to Microsoft Office Open XML by its new acronym - MooXML. Its progress through the ISO process looks like a salmon rush - but it looks like a fish, moves like a slippery slippery fish and steers like a cow (with apologies to the late Douglas Adams).
Superb Standard: And then Miguel goes and calls it a "Superb Standard". Basing most of his justification on the fact that a large quantity of existing OO.org code can be re-used to implement MooXML - take a guess why that is so. And just because the current code can handle "autospace like Word95" specifications (IIRC,the 'sz' node) is no reason to call MooXML a good standard. And multiple implementations only add to the mess, with everyone including the creator interpreting the standard as they please. Implementing it would be yet another game of 'chase the lamespec' (well, grep -i lamespec mono-svn/).
Most people who have complained about the specification has been struck down with the "let the implementors speak". But somehow it seems odd that such a specification which has been sped through ISO got a 'YES' vote from *Cuba* - a country where Microsoft (and any other US company) is prohibited from exporting any software to. A good, proper standard doesn't really need a ballot stuffing to get approved.
I mean, I've previously commented about Miguel losing relevance in the world of Free software. But this time, this is not about his opinion or Novell's patent protections - in fact, not even about the format, but about the standard for an editable document, which renders the same everywhere.
So, don't say MooXML, say NoOoxml.
--Mediocrity finds safety in standardization.
-- Frederick Crane
For once, I'm not the one being cryptic (the revenge of the apostrophes?).
Yahoo! Bangalore is throwing a hack fest on the 5th of October and all through the night. If you've ever done something with pipes, YUI, y! mail or flickr apis, this is the place to be for you. And it doesn't even matter if you like writing RoR based backends or greasemonkey funk - what matters is how it works and what it solves.
The hack session is by invite only and we've got a submission queue for you to put in your geek credentials, so make sure to put all your cool hacks in the list. And take a good look at what happened at the previous hack days for inspiration.
It is going to be a "Bring your Own Laptop" hackfest of the kind you've never seen before. To keep the tempo, we'll be trying to put up a strong team of hackers from Yahoo! to help you hack (and more importantly, appreciate the uber-coolness of your hack-in-construction).
Watch hackday.org for more announcements. Hope to see you there ... so start planning!
--To whom the mornings are like nights,
What must the midnights be!
-- Emily Dickinson
After procrastinating for nearly two weeks with the code nearly done, I've managed to find the energy (and some caramel coffee) required to fix it up for the public to use - and here it is. In the process, I also threw out all the ZendEngine2 hacks and started to use zend_user_opcode_set_handler, which should let people use this with the faster CGOTO vm core, though I would advise against using that just yet.
The new & improved inclued can dump out class inheritance dependencies (though not the interfaces, as of now). This gives a slightly bigger picture view of what files depend on what other files and provide a tree of the classes clustered into their own files. For example, this is the graph pulled out from the relatively minimal PEAR::HTML_QuickForm2 library.
The usage is as before, the gengraph.php script now has a -t option which will accept either "classes" or "includes". At the very least, it should help people documenting OOP php code. Next up are interface implementations, the data is already in the dumped files, but not output in any human readable format.
--It is a very sad thing that nowadays there is so little useless information.
-- Oscar Wilde
There are moments in my life when I'm at a loss for words.
And something like that happens.
--Take my advice, I don't use it anyway.
Now that I think, it was all like a dream - not a particularly good one, but the one you wake up & forget all about, on a monday morning. Roaming around San Francisco, Monterey and Palo Alto in Premshree's Pontiac, with Sachin snoring in the back seat, despite Chris Cornell's shrieks from the CD player. It takes an occasional look back at my photos to remind myself that no dream it was. I'll let the photographs do the talking.
And in a fleeting glimpse, I saw the clouds blow a heart to the city.
And then came the climb down and then I saw the city. And the blue, blue sea.
Sat down on the green green grass and let the world pass me by. And pass by it did.
Walked along the beach, spent perhaps the most peaceful hour of my visit watching the aerial acrobatics of the kite surfers - jumping twenty feet up and sliding along the water, masters of the wind and water.
And then next week, spent hours staring at the Jellyfish tanks at Monterey.
And that's all there is.
--The trouble with telling a good story is that it invariably reminds the listener of a dull one.
-- Sid Caesar
It's finally happening. My friends are slowly drifting away in different directions. There aren't going to be any more sessions of midnight pool, no more late night balcony conversations, no more weekend hack sessions - 'change' happens, but I can live with that. But to actually lose such friends in the milling crowd is a sad thought.
These people seem to have fallen off the planet. They've stopped blogging, have unsubscribed off many of the mailing lists and even their flickr streams are devoid of actual life, tending towards art & technique.
And reluctantly, I turned to facebook to 'bookmark' them. Despite using an online social networking site, I'm trying to keep in touch with people whom I used to meet every day.
Ironic, but completely Web 2.0.
--Friendship needs a certain parallelism of life, a community of thought, a rivalry of aim.
-- Henry Brook Adams