I have several observations regarding the newly implemented
aggregate() und overload() extensions. Depending on the
correctness of these observations you may want to reconsider the
inclusion of these extensions in the current build of PHP.

The following has not in its entirety verified in the source and
may be incorrect or incomplete. Please correct me.

Situation:

$obj = new Origclass; aggregate($obj, "Classname"); is a
function which adds all instance variables and methods from
class Classname to an object $obj of an original class
Origclass. There are variations of aggregate which allow you to
add instance variables and methods selectively by enumeration
and regex.

Observation:

aggreate and friends break the introspection in PHP, and may
interfere with serialization and sessions. This is, because
get_class($obj) returns Origclass, and no trace of Classname.
Also, $obj is_a() Origclass, but not is_a(Classname), leading to
serialization of $obj as a pure Origclass, and reinstantiation
as a pure Origclass with no methods from Classname at all.

This is the situation of serialize() in PHP 3 at a slightly
elevated level. Reminder: In PHP 3, serialize() did not record
the class of an object on serialization, and unserialize()
consequently produced an object with no methods at all, which is
in fact quite useless.

Also, because of the fine grained nature of the more advanced
variations of aggregate, there is no fast way to describe the
class or type of an object instance. The only way to completely
describe an object is to completely enumerate its instance
variables and instance methods. Essentially, get_class and
friends become meaningless.

Alternative:

aggregate is a badly designed way to introduce multiple
inheritance like functionality. There are at least two tested
ways to implement MI functionality. Statically typed languages
such as C++ set type == class and implement pure MI. Regarding
PHP, this would lead to

class C extends A, B { ... }

with the order of A and B being important. Also,
get_parent_class() would need to be modified to return
inheritance level information or inheritance graph information
together with class names in order to produce meaningful
information. Something like

        $v = get_parent_class($complicated_object); 

$v would be

        array("A" => "B", "B" => "C", "B" => "D");

for

        class A extends B ...

        class B extends C, D ...

An alternative, possibly cleaner way would be the introduction
of interfaces and categories. In this scenario we keep single
inheritance. We introduce declarations of interfaces, which may
contain a number of instance variables and functions. Interfaces
are a simple declaration of these, there is no implementation at
all in an interface.

A class may claim conformity with an interface. This means that
the class at least has all the instance variables the interface
demands and has at least implementations for all member
functions of the interface. The class may implement all this
independently or it may import a category.

A category is class-subset, and always an implementation of an
interface (you cannot define a category for which no interface
definition is being known).

Interfaces and Categories are found in some dynamically typed
languages, sometimes under slightly different names. They
separate type and class, and in order for them to function in
PHP we would need enumerative functions and predicates to
complement the new language constructs (get_defined_interfaces(),
get_defined_categories(), conforms_to($interface_name)).

Recommendation:

As-is aggregate() is a broken design, and will break existing
older functionality. It will create a number of support issues,
and later backward compatibility issues. It may inspire even
more broken "fixes" for these issues, effectively uglifying the
language itself or at least its object system.

The best would be to remove aggregate() completely, and bury it.
It should be replaced by a proper MI system, probably one for a
dynamically typed language, as PHP is such a language.

If aggregate() functionality is being used right now, and is
critical, it should be kept, properly documented, the drawbacks
spelled out in all its ugliness and its use strongly
discouraged. It should be clearly marked as obsolete from day 1,
and may be removed at any time. If someone uses this feature
despite the warning labels, this person deserves everything that
happens.



Situation:

The overload() extension allows userland code to intercept get,
set and call operations on the instance variables and instance
functions of an object. It does this by defining the special
fixed name functions __get, __set and __call in a class, which
are enabled by calling overload() on this class.

It also allows, according to Sebastian Bergmann, and in spite of
the current documentation at
http://www.php.net/ref.overload.php, __get_x(), __set_y() and
__call_x() functions in order to intercept accesses and calls to
instance variable x and method y respectively.

I haven't verified this in source, but Sebastian claims it
works.

Observation:

If this is NOT the case, I have no issue with overload(). It is
dangoerous, but it is an expert feature and the design is okay.

If overload() allows for __get_x(), though, this is bad design.
The reason for this is that we get namespace pollution and,
again (*), automatically called callback functions with a
variable name. There will interoperate badly with inheritance,
with dynamically created, undeclared instance variables and with
aggregate().

Recommendation:

If overload() indeed supports variably named callback functions
such as __get_x(), support for this should be removed in order
to avoid a number of possible inconsistencies and namespace
pollution.


End Rant, fire away...

        Kristian

(*) We had them with PHP 3 constructor names, which were an
    extremely bad idea in the first place.
-- 
Kristian Köhntopp, NetUSE AG, Dr.-Hell-Straße, D-24107 Kiel
Tel: +49 431 386 435 00, Fax: +49 431 386 435 99

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

Reply via email to