Question about autoloading
Moderator: General Moderators
- Maugrim_The_Reaper
- DevNet Master
- Posts: 2704
- Joined: Tue Nov 02, 2004 5:43 am
- Location: Ireland
There was a whole debate on the Zend Framework mailing list about __autoload() - If I remember right one point that stood out was that APC would cache the class file, but could not cache the actual class/methods it contained once they were parsed. So there is some level of caching (the file) and that's usually enough to offer a significant benefit since it skips the filesystem read. The smaller cost of using __autoload is that the file's contents are only captured and parsed after __autoload executes (i.e. after the initial parsing and opcode caching has taken place) so it misses that specific boat compared to an upfront include.
Important to distinguish between the caching of the file content vs caching the intermediate parsed code. Wish I had a thoroughly useless benchmark to point to, but I believe the difference between both isn't that much. Of course the problem with thoroughly useless benchmarks is that they tend to test specific things in isolation, not within a real application where that incredible difference amounts to squat in reality...
Important to distinguish between the caching of the file content vs caching the intermediate parsed code. Wish I had a thoroughly useless benchmark to point to, but I believe the difference between both isn't that much. Of course the problem with thoroughly useless benchmarks is that they tend to test specific things in isolation, not within a real application where that incredible difference amounts to squat in reality...
- dreamscape
- Forum Commoner
- Posts: 87
- Joined: Wed Jun 08, 2005 10:06 am
- Contact:
That is false. Of coarse autoloaded files are cached. See this follow up thread on pecl-dev: http://marc.info/?l=pecl-dev&m=116512075914909&w=2kyberfabrikken wrote:Appearently, there are some problems with autoload vs. opcode caches. I haven't had time to investigate it in details, but according to this post, using autoload, makes it impossible for apc to cache the file.
My point was this..initiates opcode caching.. so what's the difference of:both use include_once, so both will use the same opcode caching.
Code: Select all
include_once 'somefile.php';Code: Select all
function __autoload($classname)
{
// jiggery pokery
include_once($somefile);
}- kyberfabrikken
- Forum Commoner
- Posts: 84
- Joined: Tue Jul 20, 2004 10:27 am
- stereofrog
- Forum Contributor
- Posts: 386
- Joined: Mon Dec 04, 2006 6:10 am
- Maugrim_The_Reaper
- DevNet Master
- Posts: 2704
- Joined: Tue Nov 02, 2004 5:43 am
- Location: Ireland
Not quite the same. The entire source code for that request must be compiled and executed, then it picks up on any conditional (i.e. includes hidden in functions, statement blocks, etc.) includes. At this point a missing class, is just a missing class. Autoload is basically what arborint described - an error handler. It's only the original phase which went through the entire process of compilation and execution that can be fully cached as expected - everything else makes do with a lesser form of caching which is slightly slower.both use include_once, so both will use the same opcode caching.
http://sb2.info/better-solutions/techno ... erability/
cached and compiled just the same, the only difference being that the conditional includes are cached at every request (as you say, but not with a lesser cache). This is a completely negligible difference given that everything PHP is parsed and compiled at every request anyway.
cached and compiled just the same, the only difference being that the conditional includes are cached at every request (as you say, but not with a lesser cache). This is a completely negligible difference given that everything PHP is parsed and compiled at every request anyway.
Noted, thankskyberfabrikken wrote:Calling class_exists() inside __autoload makes little sense. If anything, it should be class_exists($classname, FALSE), but it's still completely redundant.The Ninja Space Goat wrote:Code: Select all
function __autoload($classname) { if (!class_exists($classname)) { (...)
- RobertGonzalez
- Site Administrator
- Posts: 14293
- Joined: Tue Sep 09, 2003 6:04 pm
- Location: Fremont, CA, USA
Awesome, because this gets to kinda what I was after in this thread... Using the SPL registry, you are not required to define an __autoload routine, correct? So if you were to do something like:Maugrim_The_Reaper wrote:Personally I stick with require_once. If I want __autoload I'll use the SPL registry (safer than using __autoload when embedded applications could already have defined it) and likely use a Phing task to strip out the require_once calls. So I can move between both worlds with little more than a command line parameter.
Code: Select all
<?php
spl_autoload_register(array('MyClass', 'ClassMethod'));
?>I gotta say this is some fantastic discussion. It covers a topic I truly had no knowledge of (let alone interest in) and I am totally digging the caliber of opinion in this thread.
- Maugrim_The_Reaper
- DevNet Master
- Posts: 2704
- Joined: Tue Nov 02, 2004 5:43 am
- Location: Ireland
I don't disagree that the difference is negligible, just that the state of the conditionally included file's cache isn't as optimal as something that was included outside any condition. Whether you term that a lesser cache, suboptimal cache, I haven't the foggiest. I just know it constantly requires extra processing for each request to define the classes/methods. The cache itself is persistent in shared memory across requests.cached and compiled just the same, the only difference being that the conditional includes are cached at every request (as you say, but not with a lesser cache). This is a completely negligible difference given that everything PHP is parsed and compiled at every request anyway.
I don't think it matters. I tend to just use a plain function thoughEverah wrote:That then does what with the MyClass class and what with the MyClass::ClassMethod method? Would it matter if that method was a static method, or if the class was essentially a static class?
- Ollie Saunders
- DevNet Master
- Posts: 3179
- Joined: Tue May 24, 2005 6:01 pm
- Location: UK
I would like to urge people to leave debates about performance out of the thread, and in fact all others. If you care about performance, get a profiler and see what takes time in your application, in it's own production environment.
Do remember that __autoload() is also class overloading. Take a few seconds to think about what that means. Here's a real world example that you can look forward to for newer versions of SimpleTest (according to MB's informal ramblings). Assume the simpletest classes have been loaded already...Here Mock_B is never defined but __autoload() can easily watch for classes beginning with 'Mock' and use the rest of the name to determine what class to generate a mock class of. And thus no longer is there need for Mock::generate() calls.
You could take this futher and dynamically generate classes with different behaviours depending on their names. You could achieve multiple inheritance this way if you wanted to. Of course it's called overloading for a reason, this kind of stuff really changes the language, often to the detriment of predictability and readability.
Not really. You aren't handling an error because the code you write in __autoload does both, prevent one from occuring, or allow it to occur without being able to handle the error (because it's a fatal). Handling an error means choosing how to deal with it, log it, display it etc. that's not what we are doing here.Arborint wrote:The are simply error callback functions for the new keyword. If there is a "class not found" error when a new is executed
Do remember that __autoload() is also class overloading. Take a few seconds to think about what that means. Here's a real world example that you can look forward to for newer versions of SimpleTest (according to MB's informal ramblings). Assume the simpletest classes have been loaded already...
Code: Select all
class B
{
public function run() { }
}
class A
{
public function runner($toRun)
{
$toRun->run();
}
}
class TestOfA extends UnitTestCase
{
public function testRunWasCalledByA()
{
$inst = new A();
$mock = new Mock_B();
$mock->expectOnce('run');
$inst->runner($mock);
}
}You could take this futher and dynamically generate classes with different behaviours depending on their names. You could achieve multiple inheritance this way if you wanted to. Of course it's called overloading for a reason, this kind of stuff really changes the language, often to the detriment of predictability and readability.
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
Just because the the likes of lastcraft can find obscure and interesting ways to use __autoload() does not change the fact that it simply calls a function when a class not found error occurs. There is no reason why that function couldn't "choose how to deal with it, log it, display it etc." It's just that the obvious intention is to put code that includes a file in there.ole wrote:Not really. You aren't handling an error because the code you write in __autoload does both, prevent one from occuring, or allow it to occur without being able to handle the error (because it's a fatal). Handling an error means choosing how to deal with it, log it, display it etc. that's not what we are doing here.
My point was it was an easily tacked on feature from a group of folks that quite honestly don't have a deep understanding or appreciation of OOP -- and it shows. That's not to say that __autoload in not a workable solution. I clearly agreed that it is. But there are many other interesting things that could have been done to solve this problem. They could have implemented include_class('path/to/file.php', 'ClassName'); or they could have made new a real overrideable thing or added a file specifier to new like $foo = new Foo() infile 'path/to/foo.php'. It could be done with Metadata given to include_path or many other ways ... but we have what we have ...
(#10850)
- Ollie Saunders
- DevNet Master
- Posts: 3179
- Joined: Tue May 24, 2005 6:01 pm
- Location: UK
What you say is correct. I just don't agree with the label of "error handler" in this case. If I wanted to log a class cannot be loaded error I would throw an exception and use set_exception_handler()Just because the the likes of lastcraft can find obscure and interesting ways to use __autoload() does not change the fact that it simply calls a function when a class not found error occurs. There is no reason why that function couldn't "choose how to deal with it, log it, display it etc."
Yes. What we have is a space to write our own code to specify what actions are performed. This is clearly more flexible than any fixed system.They could have implemented include_class('path/to/file.php', 'ClassName'); or they could have made new a real overrideable thing or added a file specifier to new like $foo = new Foo() infile 'path/to/foo.php'. It could be done with Metadata given to include_path or many other ways ... but we have what we have ...
I don't see how that is the case. That said, If you could have a separate __autoload() for each namespace and, of course, actual namespaces to go with it, that would be amazing.quite honestly don't have a deep understanding or appreciation of OOP
- kyberfabrikken
- Forum Commoner
- Posts: 84
- Joined: Tue Jul 20, 2004 10:27 am
spl_autoload_register takes a callback as argument. A callback is not validated until the time, where it's called. So if the class MyClass isn't defined, once autoload is invoked, it will fail. Thus, you'd want to explicitly load that particular class beforehand.Everah wrote:So if you were to do something like:That then does what with the MyClass class and what with the MyClass::ClassMethod method? Would it matter if that method was a static method, or if the class was essentially a static class?Code: Select all
<?php spl_autoload_register(array('MyClass', 'ClassMethod')); ?>
A callback can also be a method on an object instance. So this is valid as well:
Code: Select all
class MyAutoLoader
{
function loadClass($classname) {
(...)
}
}
spl_autoload_register(array(new MyAutoLoader(), 'loadClass'));- dreamscape
- Forum Commoner
- Posts: 87
- Joined: Wed Jun 08, 2005 10:06 am
- Contact: