Re: Class and interface location
| From: | Steve Staples | Date: | Wed, 19 Jan 2011 13:29:39 +0000 |
| Subject: | Re: Class and interface location | ||
| References: | 1 | Groups: | php.general |
| Request: | Send a blank email to php-general+get-310861@lists.php.net to get a copy of this message | ||
On Wed, 2011-01-19 at 01:07 -0600, Larry Garfield wrote:
> Hi all. I'm trying to come up with a solution to an architectural problem I
> could use some extra eyes on.
>
> I have (or will have) a large code base with lots of classes, spread out over
> many optional plugin components. These classes, of course, will have
> interfaces on them. These classes will, of course, lazy-load using PHP's
> autoload capability.
>
> What I need to know is which classes implement which interfaces, so that I can
> load and use "all classes that implement interface Foo".
>
> There are a couple of approaches that I've considered, all of which I dislike
> for one reason or another.
>
> 1) Magic file naming. That is, any class that implements interface Foo lives
> in a $something.Foo.inc file, or some similar pattern. This has a number of
> problems. First, it means a huge number of file_exists() calls to determine
> if a given potential class exists, and then disk hits to load those files.
> While that information is possible to cache, it also means that we cannot have
> a class that implements two of the interfaces I'm interested in (a feature I
> will need) because then it would have to live in two files, which is clearly
> impossible.
>
> 2) Reflection. PHP makes it quite easy to get a list of all loaded classes,
> and to get a list of all interfaces that a loaded class implements. The catch
> there is "loaded". Reflection only works once you've loaded the code file
> into memory. Once you've done so, you cannot unload it. That means the code
> is sitting there in memory wasting space. Given the size of the code base in
> question, that could easily blow out the process memory limit. Even if we
> cache that information we derive from reflection we still have to load it the
> first time (or periodically when rebuilding the cache), which will blow the
> memory limit. The only alternative would be to have some sort of incremental
> rebuild across a multi-request batch process, the complexity of which makes my
> skin crawl.
>
> 3) Static analysis. Instead of reflection, either tokenize or string parse
> all files to determine what classes implement what interfaces and then cache
> that information. We are actually using this method now to locate classes,
> and it works surprisingly well. Because we never parse code into memory it
> does not ever spike the memory usage. However, it is impossible to determine
> if a class implements a given interface by static analysis unless it declare
> so itself with the implements keyword. If it does so indirectly via
> inheritance, either via the class or via the interface, it would not find it.
> That necessitates that any "detectable" classes must explicitly themselves
> declare their interfaces, even if it is redundant to do so. I don't like that
> approach, but it's the first one that strikes me as even viable.
>
> 4) Explicit declaration. In this approach we detect nothing and rely on the
> plugin developer to do everything. That is, they must provide somewhere
> (either in code or a configuration file) an index of all classes they offer,
> the interfaces they implement, and the file in which they live. While this
> makes the implementation easy, it is a huge burden on the plugin developer and
> I'm quite sure they'll forget to do so or get it wrong on a regular basis.
>
> 5) Wave a wand and let the magic ponies figure it out. I wish. :-)
>
> Can anyone suggest a better alternative? At the moment option 3 seems like
> the most viable approach, but I'm not wild about the implied performance
> impact nor the potentially redundant interface definitions it would require.
>
> --Larry Garfield
>
My suggestion, would be for #5. The magic ponies do wonderful work.
:)
Steve (TheStapler) Staples.