Phemto is throwing CannotFindImplementation

Hi,

I’ve got an interface called IRequest and a class called Request which implements IRequest. Then I’ve got another class which takes a IRequest as a paramter to its constructor. This second class is created using Phemto like this:

$injector->create("SecondClass");

I’ve wired Phemto with $injector->willUse(“Request”); but I’m still getting CannotFindImplementation exception when trying to create SecondClass. Other dependencies is working. I’ve checked that I’ve spelled IRequest and Request correctly where it is used.

Anyone know what could be wrong?

EDIT: Realised maybe this don’t belong in the application design forum but in the main php forum.

Thanks in advance!

-Martin

Also just noticed that if I do $request = $injector->create(“Request”); before trying to create the SecondClass it does work. When I remove it the exception is thrown again.

Sounds like an include problem.

Is the interface defined before the call to $injector->create(“SecondClass”); ?

I’m using an autoloader. I’ve noticed now that no dependencies work unless I create the with $injector->create(“Class”) first or new Class();

Shouldn’t Phemto use my autoloader too? It is defined before I start using the injector.

Not certain, as haven’t used Phemto that much.

A chicken & egg problem?
Phemto determines what implementations to create by what is available (loaded). Autoloading only happens when Phemto has determined which class to instantiate.

But I tought I told it what to use by using $injector->willUse(“Request”); then when it sees IRequest it should know that it is to create a Request object and send it.

I don’t think Phemto knows that Request is concrete implementation of IRequest though?

I thought it would, from the docs at http://phemto.sourceforge.net/quick-start.php:

Phemto identifies the “Bar” hint then searches its internal registry for a concrete implementation. Anything “greater than or equal to” Bar in the class hierarchy will do. If Bar is an interface any class which implements Bar is a viable candidate. If Bar is a class, ordinary or abstract, anything with Bar as an ancestor can be used including, of course, Bar itself (although that rather defeats the purpose). Usually you’ll want to type hint to interfaces.

Initially, Phemto doesn’t know anything about Request because it hasn’t been included. When it’s asked to fill an IRequest hint it doesn’t know of any candidates.

When you instantiate Request directly, autoload does it’s thing and now Request is in the included classes list. Next time Phemto is asked “give me something implementing IRequest”, it can find the Request class.

That’s the current behaviour. Perhaps it could be improved - I never use autoload and so I’ve never encountered any of these problems. Will need to take a look at that.

I’m not sure about the general opinion but I would like it to try to create an object of the class and fail only if it can’t.

OFFTOPIC:
Also, have you thought about brining Phemto to github so more can easily contribute? :slight_smile:

That’s a fundamental problem if you use autoload. Although Phemto has been configured to use a Request, it doesn’t know that Request implements IRequest. It won’t know anything about any class hierarchy to which Request might belong until Request is included.

One way to deal with that would be to search the filesystem for the Request class at the configuration stage (in fact this would trigger a whole cascade of filesystem queries to discover the full inheritance hierarchy). Although that would work, it doesn’t sound very efficient. Might not really matter though.

Alternatively, at the configuration stage, you could tell Phemto that Request can fill any IRequest dependencies at the cost of making configuration slightly more complicated.

That’s all just off the top of my head. I’ve never actually used autoload and I’ll need to read up on the details.

Git-svn allows you to use git locally. I agree git is nice to try out experiments or ideas for patches without messing up the main trunk.

Ah, now I understand why you don’t know about the class hierarchy.

Alternatively, at the configuration stage, you could tell Phemto that Request can fill any IRequest dependencies at the cost of making configuration slightly more complicated.

So I can change the config to make what I want work? How would I do that? I tried with $injector->whenCreating(“Router”)->willUse(“Request”); and Router take a IRequest in it’s constructor. However that didn’t work.

My comments are quite confusing - sorry. I was thinking out loud how we might add autoload capabilities to Phemto. At present Phemto just can’t deal with this problem.

This is the current autoload test suite:


class AsMuchAsPossibleWorksWithAutoload extends UnitTestCase {
}

That’s it…

I’d very much like Phemto to be a useful tool. I’m in the middle of something which is taking longer than it should (as always). I’ve also just got a new mic which I won’t be able to put down for a few days. Might take a couple of weeks to come up with something.

I think its something like


$injector->forType("IRequest")->willUse("Request")

Ah cross posted with McGruff above, and he certainly knows more about Phemto than I do.

Hi…

I’m a bit late to this thread, but it looks like you guys have got everything figured out :).

Yes, I never got around to coding that autoload test. I was hoping that autoload would be killed off by PHP6 bytecode caching before it became an issue ;).

Right now you are in workaround land. If you send us a failing test, say by filling out the empty one McGruff posted, I’ll hack around a bit and see what I can come up with. It probably means one of the following…

  • Phemto replaces autoload in some way by having an Autoload factory.
  • Phemto can tap into autoload in some way.
  • We add a configuration semantic (my least favourite).

If anyone wants to help, just mail me a Sourceforge ID. It’s only a couple of hundred lines of code, but I must warn you it’s seriously twisted.

Calling class_exists will implicitly trigger autoload. Just stick it right before you create a ReflectionClass.

Hi…

class_exists()? Oh, does the Reflection code not do that already?

Still have the problem that the (autoload) code has to find a class name from an interface. This probably needs developer input as there seems to be no way to get a classes interfaces without touching the source file.

  • As autoload should be under the control of the application developer, either directly or through an interface provided by the framework, they should be able to adapt their autoload code to load candidate classes from an interface. Messy though as it would duplicate Phemto’s job. Bringing in a new component would mean adding Phemto hints and modifying autoload code. Ouch.
  • An autoload style Lazy factory for Phemto at least places the configuration in one place. Not sure how it would work. Looks like it would completely override the current search mechanism.
  • It looks like the simplest solution is for the developer to add another directive in the wiring file or just manually include the lower level classes there. I can add the class_exists() hack if needed. It doesn’t look like too much wiring would be needed in practice, although it rather defeats part of the purpose of autoload.

How do people use autoload? I’ve always avoided it because it seems Autoload_Makes_For_Painful_ClassNames.

yours, Marcus

Nope.

The use case for it, is where you have a configuration that specifies a concrete class dependency. The autoloader can then load the concrete class. You’re quite right that there is no way to resolve from interface to class, but I think that’s fine too. There can be multiple candidates for an interface, so that decision should require a developer.

This is one of the reasons like using closures, can explicitly insert a require/include before instantiating.

Great that it has caused some discussion. I’m not sure how I would like it to work. Will look at it some more when I get home.

I use autoload that I’ve got a couple of folders added to the include_path and then I name class filenames like the class: User.php. Not the best way but it works for me.