On Mar 12, 2010, at 9:28 PM, Chris Trahey wrote:
> The old class is still there, think of it as if the inserted (overloading)
> class extends the base (overloaded) class and any classes the were extending
> the base now extend the inserted class. So as far as the runtime, it's
> run-of-the-meill inheritance. Methods that are not re-implimented in the
> inserted class are called in the original class, etc.
> 
> It could be implemented either at the time a class is loaded (when we see
> 'overloads' keyword) or perhaps in a function call:
> overload_class('Library_Class', 'My_LibClass_Overload');
> 
> As for conflicts where multiple overloads are attempted, they could be in
> sequence, such that you'd end up having an inheritance chain like this:
> 
> called_class <-- second_overload <-- first_overload <-- Library_Class <--
> etc.

In Objective-C, one did this in the older days by calling NSObject's 
-poseAsClass: method, which would replace the class you sent it to with the 
class you specified. Nowadays that approach is strongly discouraged in favor of 
method swizzling, a technique by which you replace a specific class' 
implementation of a single method with your own (which, with a minor bit of 
extra work, can call through to the original). Internally, it's done by 
replacing the function pointer in the class' method table with a new one and 
returning the old one. Zend's implementation is slightly more twisted than 
libobjc's, amusingly enough, but it's still doable. This is the typical way for 
a dynamic language to solve the problem you've described. In PHP I believe the 
necessary work is already implemented in runkit via the function 
runkit_method_redefine(). You need only install that, or refer to it to make an 
extension of your own. If you want this functionality in core, file a feature 
request. (I'm personally in favor of making a lot of runkit's dynamic class 
tweaking abilities core).

As far as I understand your issue, this technique would solve it cleanly.

> On Fri, Mar 12, 2010 at 8:11 PM, Etienne Kneuss <col...@php.net> wrote:
> 
>> Hi,
>> 
>> On Sat, Mar 13, 2010 at 2:50 AM, Chris Trahey <christra...@gmail.com>
>> wrote:
>>> Perhaps a new concept in class-based OO programming, I'm not sure.
>>> 
>>> Depending on your perspective you could call it ancestor overloading (or
>>> upstream overloading) or class underloading.
>>> 
>>> 
>>> We are increasingly developing with the aid of frameworks & libraries. In
>>> fact, this idea came from my current project using the Zend Framework.
>>> 
>>> These libraries, while greatly extensible, are also fairly
>> self-extending.
>>> That is, they include many classes that extend many classes, which is
>> great.
>>> 
>>> As consumers of these libraries, we can extend the classes and consume
>> the
>>> API however we please, but there is one sticking point.
>>> 
>>> We cannot change classes that many other classes extend without extending
>> or
>>> changing each child class and then making sure that our code uses the new
>>> class.
>>> 
>>> 
>>> For a concrete example, I was working with the Zend_Form_Element
>> subclasses,
>>> and I realized that I wanted to change some of the default behavior (in
>>> Zend_Form_Element).
>>> 
>>> - at this point I will assume the reader understands why I wouldn't want
>> to
>>> just start changing the Zend library files -
>>> 
>>> There are many subclasses of Zend_Form_Element. If you want to change the
>>> default behavior for all of them, you have 3 choices currently:
>>> 
>>> 1. Directly edit the Zend_Form_Element file in the library, -bad for
>> updates
>>> & other projects that use the library
>>> 
>>> 2. subclass Zend_Form_Element and change declaration of the descendants
>> to
>>> extend new class - same problems
>>> 
>>> 3. extend each child class and implement those subclasses in your app
>> code
>>> -very tedious and TONS of repeated code, breaks consistency of API for
>>> developers.
>>> 
>>> 
>>> There could be a better way, if we could insert a class into the family
>>> tree.
>>> 
>>> And that's the heart of this idea, so I'll repeat it:
>>> 
>>> * insert a class into the family tree *
>>> 
>>> 
>>> Image we do it using an alternative keyword to "extends", such as
>>> "overloads".
>>> 
>>> 
>>> Example:
>>> 
>>> 
>>> class Library_Class { }
>>> 
>>> class Library_Subclass extends Library_Class {}
>>> 
>>> and then:
>>> 
>>> class My_LibClass_Overload overloads Library_Class{}
>>> 
>>> 
>>> Now new instances of Library_Subclass actually extend
>> My_LibClass_Overload,
>>> which "extends" Library_Class. The developer would then code
>>> My_LibClass_Overload as if it were declared like this:
>>> 
>>> class Library_Class {}
>>> 
>>> class My_LibClass_Overload extends Library_Class {}
>>> 
>>> class Library_Subclass extends My_LibClass_Overload {}
>>> 
>>> 
>>> But indeed the declaration of Library_Subclass would *not* have to
>> change.
>>> 
>>> 
>>> This way developers could "extend" default functionality and have
>> *existing*
>>> library classes pick up the new functionality without redeclaring
>> anything
>>> in the library.
>>> 
>>> Downstream classes would still override any methods that they redeclare.
>> If
>>> you wanted to have end-point classes in the library have different
>> behavior,
>>> you would overload them instead, such as
>>> 
>>> class My_LibSubclass_Overload overloads Lib_Subclass {}
>>> 
>>> 
>>> The benefit is that the application code can still consume "standard"
>>> classes, such as Library_Subclass and not need to know or care about the
>>> extended functionality.
>>> 
>>> 
>>> Going back to my concrete example, my code could then still use
>>> Zend_Form_Element_Text, but benefit from the modifications I added,
>> without
>>> me having to touch the library code.
>>> 
>>> 
>>> I hope I've explained clearly what this could look like. I'm a younger
>>> developer, so forgive me if I'm rough on the terminology -perhaps
>>> overload/underload is not the best word for this functionality. Also, I'm
>>> not sure if there are other class-based OO languages that allow this kind
>> of
>>> behavior... Prototypal languages perhaps, as is the case with javascript
>> and
>>> the Obj.prototype which (combined with anonymous functions) allows you to
>>> extend the "base" functionality of other objects that "extend" it.
>> 
>> Even though it might look appealing from a framework user perspective,
>> it looks fishy from a language design perspective. It sounds like
>> you're trying to fix a framework design lack by a language trick.
>> 
>> For the fishy part: what happens to the old class? what about static
>> method calls on that old class? What if two classes overwrites the
>> same class? Basically it would mean there is no way to know at compile
>> time which class new Foo; is supposed to instantiate.
>> 
>>> 
>>> 
>>> Thank you for your comments and thoughts!
>>> 
>>> 
>>> Chris Trahey
>>> 
>>> Web Applications Developer
>>> 
>>> Database Administrator
>>> 
>>> CSISD [Technology]
>>> 
>>> 
>>> footnote: I sent this message from a different address and it did not
>> show
>>> up. I tested sending to internals-h...@lists.php.net and did not get a
>>> response -so I assume there is an outgoing issue on my other server's
>> side.
>>> Forgive me if this message shows up again.
>>> 
>> 
>> 
>> 
>> --
>> Etienne Kneuss
>> http://www.colder.ch
>> 

-- Gwynne


--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to