Phemto and autoload

I am using Phemto as DI in my application.

I also begin use Zend_Loader as autoload. And there is one pitfall with it.

I need to add class loader call every time I use $injector->willUse()
like this:


$injector->willUse('MyFW_Session_General');
Zend_Loader::loadClass('MyFW_Session_General');

Is it possible to inject class loader to Phemto? Or how can I implent this in the most correct way?

Thanks!

Thanks a lot for this fix and deep explanation.

Hi…

Patched and uploaded as Phemto alpha10. class_exists() is indeed needed. This should work now. It does for the sample test case you sent me. Thanks for that.

For the OCD sufferers amongst you, this was the problem:

Phemto keeps a cache of all Reflection lookups for performance reasons. The cache uses get_declared_classes() on instantiation to build the list of candidates. It uses this list to index interfaces against implementations and vice versa. Autoload messes with that quite nicely as the available classes are being built up gradually rather than all included at the start. The cache is way out of date by the time an interface lookup is needed.

class_exists() forces a code load for each declaration of Phemto’s willUse(). This may load more code than needed if the implementation is never needed. I doubt that matters for the half dozen or so calls to willUse() that you typically need for a wiring file sans autoload.

I can probably get around loading unneeded code by having the reflection cache refresh itself as it goes, but that involves a bunch of array_diff()'s against get_declared_classes() which is probably slower.

A catch is that when using autoload, you have to declare the implementation with willUse() even when there is only one candidate for an interface. A shame, but that’s intrinsic to the magic of autoload. Phemto will never have a complete picture of the available implementations in this case.

More annoying is that if you forget willUse(), the Phemto error message is not so clear. I need to add better error reporting anyway, so I’ll defer this until beta.

Thanks for everyone’s help tracking this issue down.

yours, Marcus

Dear Marcus,

Seems that adding class_exists could solve the problem.


class Context {
    ...
    function willUse($preference) {
      class_exists($preference);
      ...
    }
}

Hi…

I can’t figure out what the problem is :). I’ve just installed Zend so that I can try out the posted test case. Still working on it in the gaps between real life.

yours, Marcus

Hi…

It tends to lead to classes having a subtle dependency on the file system. It also tends to distort class naming. When it doesn’t distort the name (a good thing) you need to maintain a global mapping of names to locations and tracking down the code can get mysterious.

Basically it doesn’t scale and leads to bad code.

By contrast, require_once(dirname(FILE) …) is scoped, explicit, leads to the file system following a proper package structure and doesn’t pressure class names.

yours, Marcus

Is there a reason for that?

Marcus, I replied to your post in a separate thread so as not to further derail this discussion.

Hi…

I just added some autoload tests to Phemto and they all passed. Uh?

Anyway, I’ve released it as Alpha9. I think I need more detail on your actual problem. I’ll chase up the older thread tomorrow and see if I can come up with a test that breaks.

yours, Marcus

class_exists will trigger autoload, unless explicitly told to do otherwise. You can simply call that in the factory and throw an exception if it returns false. That also downgrades the fatal error to a catchable exception, which is a nice thing imho. See: http://github.com/troelskn/bucket/blob/master/lib/bucket.inc.php#L113

Hi…

And also the location in the wiring files :). It’s on my mental TODO.

I’m back to paid work right now, so I may not be able to try this until tomorrow.

yours, Marcus

Thank you very much for responce.

I’ve downloaded the newest version, but the error still remains.

Look at the attachement. Just try to run
php test.php

It should work. Then go, comment Zend_Loader::loadClass lines and you’ll get an error.

PHP 5.2.13 (cli), Ubuntu 10.04

And another note.

It could be helpful if instantiateParameter($parameter, $nesting) would add nesting information to the error message.

I’ve created rough hack like this:


function instantiateParameter($parameter, $nesting) {
        if (isset($this->named_parameters[$parameter->getName()])) {
            return $this->named_parameters[$parameter->getName()];
        }
        if ($value = array_shift($this->unnamed_parameters)) {
            return $value;
        }
        print_r($parameter);
        print "\
-------------\
<br/>";
        print_r($nesting);
        die('Missing dependency: '.$parameter->getName());
        //throw new MissingDependency($parameter->getName());
    }

May be there is more beautiful way to provide such a message.

Thank you!

Hi…

Could you send a code snippet that works with the loader and not when commented out? Apparently I just have to add a get_class() call somewhere to trip the autoload (the subject of a previous thread). I can then release another tarball once I’ve added the fix.

I don’t tend to use autoload mechanisms, so this is one of the features that got left until last (hence the alpha status).

yours, Marcus

p.s. It’s possible to subtype the Phemto factory mechanism to get what you want, but you’d still end up with some extra code.