php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #5377 Using :: on instance functions / future devolpment of PHP
Submitted: 2000-07-05 15:35 UTC Modified: 2000-07-17 12:45 UTC
From: waldschrott at kiffen dot de Assigned:
Status: Closed Package: Feature/Change Request
PHP Version: 4.0 Latest CVS (05/07/2000) OS: all
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: waldschrott at kiffen dot de
New email:
PHP Version: OS:

 

 [2000-07-05 15:35 UTC] waldschrott at kiffen dot de
taken from Kristians (kk@netuse.de) mail

Uses of :: in an instance
=========================

Using :: on instance functions
------------------------------

If used in an instance of a class, :: should be able
to address a shadowed method in a superclass of the
current instances class. That is,

class a {
  function somef() {
   print "I am somef() in a\n";
  }
}

class b extends a {
  function somef() {
    print "I am somef() in b\n";
  }

  function otherf() {
    $this->somef(); // will print "I am somef in b"
    a::somef();     // will print "I am somef in a"
  }
}

$b_instance = new b;
$b_instance->somef(); // will print "I am somef in b"

This is useful to address a shadowed instance method 
in a superclass of a class, for example when extending
an initalizing function. Note how the name of the
superclass is mentioned multiple times in b, which is
a denormalization. Changing the name of a classes superclass
will make changed in many code locations necessary.

It would be much more elegant if you had a pseudo variable
$super instead which could be used to reference a classes
superclass as in

class b extends a {
  function somef() {
    print "I am somef() in b\n";
  }

  function otherf() {
    $this->somef();  // will print "I am somef in b"
    $super->somef(); // will print "I am somef in a"
  }
}

Alternatively, it would be useful if the class and
function names around a T_PAAMAYIM_NEKUDOTAYIM need
not be T_STRING, but can be variable references,
facilitating syntax like

class b extends a {
  function somef() {
    print "I am somef() in b\n";
  }

  function otherf() {
    $c = get_parent_class(); // returns (string) "a"

    $this->somef(); // will print "I am somef in b"
    $c::somef();    // will print "I am somef in a"
  }
}


Using :: on instance variables
------------------------------

This could be used to address shadowed instance variables
as well, but the concept of "shadowed instance variable"
is only useful when you consider static initalizers of
instance variables. That is, consider

class a {
  var $some_var = "initializer in a";
}

class b extends a {
  var $some_var = "initializer in b";

  function showvar() {
    print $this->some_var; // will print "initializer in b"
    print a::some_var;     // will print "initializer in a"
  }
}

That would be sensible, but if it doesn't work that way,
it is of little importance.


Uses of :: outside of an instance
=================================

Class functions
---------------

Outside of an instance, :: does make sense only to address
(Objective C name:) class functions alias (Java name:)
static class member functions and (Objective C name:) 
class variables alias (Java name:) static class member variables.

A class function/static class member function is a function
which can be called in a class even when no instance of
that class is available. Such functions are useful for a
variety of purposes (see any Objective C runtime documentation
or any Java handbook), but they can be emulated with plain
functions (raising namespace issues).

Example use:

class a {
  function sfunction() {
    print "I am sfunction in a\n";
  }
}

a::sfunction(); // will print "I am sfunction in a"

A class function should be able to call other class functions,
but cannot call instance functions and therefore not refer to
$this, as there is no instance. It is of little use to create
a default instance (of a default class), raising an error
condition would be more sensible.

Class variables
---------------

A class may have class variables. Such variables are useful to
keep track of all instances of a class, for example a database
class keeping track of all database links in all database class
instance objects, or for example a Drawable class, keeping track
of all Drawable instances and providing a draw_all() class
function. 

This can be emulated using a Keeper class with a single
instance and putting all instances into the Keeper after creation,
but having it in a class would still be useful in some cases.

class a {
  var $class_var;
}

a::class_var = 10;

Assorted problems
=================

:: outside of classes introduces problems with variable interpolation,
as the construct is no longer introduced by $ signs. This leads at least
to strange syntax and may be creating other, more serious problems as
well.

In Smalltalk and in Objective C, classes are objects, too. Their
class is named "Metaclass" and Metaclass implements a number of
standard functions for dealing with Classes. An instance of
Metaclass is a class, and belongs to the class Metaclass as well,
terminating this recursion.

That is, in Objective C and Smalltalk

  $o = new SomeClass;   // $c is an instance of the class SomeClass
  print $o->get_class_name(); // will print SomeClass

  $c = $o->get_class(); // does not return a string, but an object
                        // which is the class SomeClass.
  print $c->get_class_name();  // will  print MetaClass

  $m = $c->get_class(); // does return the class object for $c,
                        // which is the MetaClass object
  $m->get_class();      // will print MetaClass, also.


Somehow a similar Semantic should be defined for PHP4 as well. It
need not be identical, but it should be defined to clear things up.
And it should be defined in a way that makes things function in
a sensible way (not just "because the implementation happens to be
this way").

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2000-07-06 14:56 UTC] waldschrott at kiffen dot de
////Taken again from a newer posting of Kristian (kk@netuse.de)

Some definitions for a language that is not quite like
Zend/PHP4:

Let C by a class,
let $o = new C; be an object, an instance of C.

The object $o have some instance variables named
o1, o2, o3. At the moment, these are being addressed in
PHP using the following arrow syntax:

	$o->o1 = "something";
	$o->o2 = 17;
	...

The class C could have some class variables c1, c2, c3.
These are variables which belong to the class, not the
object and are shared by all instances of C. One could
probably write

	$C::c1 = "something";
	$C::c2 = 17;
	...

to address these values. Using

	C::c1 = "something";
	...

would be a bad idea because PHP relies on the $ prefix
for variable names to do string interpolation.

To make things consistent, the instance methods im1, im2,
im3 and so on of $o are being called using

	$o->im1();
	...

and so on. Thus, writing

	C::cm1();
	...

to call the class methods as we currently do in PHP would
be inconsistent. It should be orthogonal, thus the syntax
should me

	$C::cm1();
	...

to call class methods, if possible.


Now, what are class methods and what are class variables?

A class method is a method that can be called without having
an instance of that class. This method should not be able to
use instance methods, as there is no instance. It should not
be able to use instance variables, for the same reason. It
may be possible to use "$this" internally in a class method
to refer to other class methods of the same class, and to
refer to other class variables of that class. This would be
useful, as there will be less references to the hardcoded
classname in the code - the class name should be used only
in one place, the class definition "class <name>" or
"class <name> extends <name'>".

I assume this is implemented by making a class an object, too
(So of what class is the class object? Metaclass! So is
 Metaclass, terminating the recursion. Have a look at the
 Smalltalk object model for detailed information - this is
 an bytecode interpreted single inheritance language just
 as PHP4, so it should  be adequate.)

If all classes are instances of Metaclass, they would inherit
a number of methods from Metaclass, and these methods would
be what is currently available as Zend functions such as
get_class() and get_parent_class. Even new could be a
method of Metaclass, leading to constructs such as

  $o = $C::new();

but this is for the OOP stasi only. It shows how orthogonal
things can be in such a model.

There is no need at all for class methods and class variables,
PHP is already turing complete. Now that you have references,
you can emulate class methods and class variables for any given
class C by manually creating a class C_Keeper, of which you
create only a single instance, and which you use to implement
all class methods and variables.

Having this as part of the language makes certain things easier
to code. If you are going to modify the PHP object model, you
should stop now, though, and think hard. You should also read
up on Smalltalk and on Objective-C as these are the object
models that make the most sense in a PHP context. You should
have a look at C++, also, to see an object model that is overly
complex, fails to deliver some critical features, and generally
sucks. If you are interested, I can provide you with some
information on that, but I won't rant about C++ unasked here.

Only after having decided on a sensible object model for PHP
we should go and implement more, to avoid confusion in the
language.



 [2000-07-06 16:04 UTC] waldschrott at kiffen dot de
> KK>> The class C could have some class variables c1, c2, c3.
>  > What is "class variable"? How is it different from globals?

 In scope. A global uses up a name in the global namespace. A
class variable uses up a name in the class namespace. If you
think of classes as instances of a class Metaclass, this will
be exactly defined.


> KK>> $C::c1 = "something";
> KK>> $C::c2 = 17;
>  > Does this change it in all instances of class C? If so,
I fear there's no
> good way to do it in PHP.

 Think of an object $o with instance variables $o->o1, $o->o2,
$o->o3, $o being an instance of class C as a hash of the
following form:

$o["o1"]  = 1;
$o["o2"]  = 2;
$o["o3"]  = 3;
$o["isa"] = &$c; // reference to Class C.

$o also has the instance methods $o->im1(), $o->im2(), and
$o->im3().

Think of a class C as a hash of the following form:

$c["name"] = "C";
$c["im1"]  = &im1(); // reference to $o->im1();
$c["im2"]  = &im2();
$c["im3"]  = &im3();
$c["isa"]  = &$m; // reference to Class Metaclass (here
called m).

The class contains pointers to all methods available to
instances of C. It can also contain additional pointers
to functions not available to instances, but only to the
class itself, and to variables not available to instances,
but only to the class itself. If you change these variables,
they will change for the class, or, as you say, for "all
instances",
as they are not kept in the instance, but in the class.

$c["cm1"] = &cm1(); // marked specially so that this can be
                    // distinguished from im1. This is a
class method.
$c["c1"]  = 1;      // marked specially, so that this can be
                    // recognized as a class variable.

Then there is the class Metaclass, here called $m. This contains
all instance methods available to class objects such as $c.
Such methods would be get_class(), get_parent_class(),
or new().

Again, have a look at the Smalltalk model, or at Objective-C.
They explain it much better than I do.

http://www.amazon.com/exec/obidos/ASIN/0201136880 "Smalltalk
80: The language"

http://developer.apple.com/techpubs/macosx/macosx.html
"MacOS X Developer Documentation"

http://developer.apple.com/techpubs/macosx/System/Documentation/Developer/Cocoa/ObjectiveC/ObjC.pdf
"Objective-C Language"


> KK>> $C::cm1();
> KK>> ...
> KK>> > KK>> to call class methods, if possible.
>  > No. $var() means "take name from var, and call method
by this name".

 Which this does.


> Using such a method looks like a bad hack to me. Why to
have a class if
> you don't instantiate it? Just to call it a "class"? Call
it "utility
> library" and leave classes alone.

 This is not what this is about. There may be instances of
class. Class variables can use useful to track instances
of the class. I gave examples in a previous post, naming
a database connection class like DB_Sql, keeping references
to all open database handles in a class variable and a class
Drawable, keeping references to all drawable instances in a
class variables. Class function would then be useful to
invoke actions on all instances, or to ask for values of
class variables in a functional manner (accessor functions).

I also stated that you could manually code a C_Keeper for
each class C, create a single instance of this and use this
to emulate class variables and class methods of C as instance
variables and instance methods of C_Keeper. This is slightly
boring, but a functioning workaround.

 [2000-07-06 16:43 UTC] waldschrott at kiffen dot de
// another mail...

That is another weakness in the language, which leads to
abominations such as stdClass. PHP reports the TYPE of
"$o = new C;" as "object", but does not report the CLASS
of $o. That means that classes are not types and when you
set the type of a variable to object, it has no class at
all.

What is an object? Think of it as I have outlined in a
previous post, as a hash containing all instance variables
plus a hidden variable "isa" pointing to the class of
that object. You can serialize() that easily to
(classname, name/type/value of all instance variables).

What is a class? Think of it as I have outlined, as
a hash containing all instance methods, plus all
class variables, plus all class methods plus hidden
instance variable "isa" pointing to Metaclass. At the
moment you cannot properly serialize() that. One
way to serialize that is to generate autoloader
code for the include file defining that class, but
that assumes a 1:1 relationship between classes and
files.

It would be much more elegant to serialize() a class
as the values of all class variables, plus the compiled
bytecode of all instance and class functions. That way
you break the 1:1 relationship between classes and
include files, you get an easy way to manipulate precompiled
bytecode, and you solve the undefined class problem
when using session variables, as the code of serialized
objects becomes part of the session (and then you
store session objects in shared memory, and the magic
really happens, but that is for another discussion).

 [2000-07-17 06:20 UTC] waldschrott at kiffen dot de
another mail from kristian(kk@netuse.de) on "necessity of super":

 $super would be like $this, but referencing attributes and
methods of the direct parent class of a class.

Mostly, it would allow you to call methods that have been 
overridden, like

-----
class a {
  function x() {
    print "x of a\n";
  }
}

class b {
  function x() {
    print "preamble x of b\n";
    $super->x();
    print "postamble x of b\n";
  }
}
-----

This is currently possible using namespaces as in
a::x(), but that makes it necessary to denormalize
the class relationship, as now the name of the superclass
is coded into the subclass not only in the extends-statement,
but also in many additional places. That propery of the
current syntax makes changed in the class hierarchy
overly hard.


$super would have allowed you to chain constructors, had PHP
given constructors fixed names instead of using the classname
as constructor name, that is, you could have written

----
class b {
  function __ctor() {
    print "ctor of b\n";
    $super->__ctor();
  }
}
-----

Instead you get abominations as

-----
class A {
  function A() {
    print "I am the ctor of a\n";
  }

  function B() {
    print "I'm just an innocent function, not a ctor\n";
  }
}

class B extends A {
}

$x = new b;
-----

which prints

-----
X-Powered-By: PHP/4.0.2-dev
Content-type: text/html

I'm just an innocent function, not a ctor
-----

which is certainly not expected nor desired.


In PHP3 and PHP4, the rule for ctors is currently
"The name of the ctor function is the same as the
name of the class". That would make it necessary to
write a new ctor for each subclass, in order for the
subclass to initalize itself properly. Had the ctor
name been constant (e.g. __ctor), that wouldn't have 
been necessary, as the ctor would have been inherited 
with a proper name automatically.

In PHP4, the ctor rule was amended with an exception:
"If the superclass has a ctor, but the subclass has no 
function named just as the subclass, the superclass ctor 
is called despite having the wrong name."

-----
kk@wwwx ~ $ Source/php3/php
<?php
class A {
  function A() {
    print "I am the ctor of a\n";
  }
}

class B extends A {
 }

$x = new B;
X-Powered-By: PHP/3.0.17-dev
Content-type: text/html

kk@wwwx ~ $
-----

but

-----
kk@wwwx ~ $ Source/php4/php
<?php
class A {
  function A() {
    print "I am the ctor of a\n";
  }
}

class B extends A {
 }

$x = new B;
X-Powered-By: PHP/4.0.2-dev
Content-type: text/html

I am the ctor of a
-----


So should it be fixed?

Well, the object system in PHP currently is a mess: Classes are not
types, they are just hashes with functions. Some people are currently
using functionless objects as fancy array syntax, writing $o->a instead
of $o["a"]. This very elegantly combines the ineffiency of objects
with the lack of the ability to use array functions on them.

Also, references are needed to deal properly with objects, and object
networks (data structures made from objects, hashes, arrays and other
container types). Additionally, ctors and dtors are handled in a 
suboptimal fashion or are even lacking completely. 

Although a mess, the current object system is a great improvement
over the PHP3 non-object system: Even if not first class citizens,
we do have references, and we do have an introspection API which is
mostly complete, even if somewhat asystematically organized.

I think the PHP object system should be fixed, and this can only
be done with either breaking compatibility or by creating a second
new object system with a different syntax. The fixed object system
should be planned, not grown, and it should focus on dealing with
componentware. That is, it should delay as many decisions as long
as possible (into runtime, even call time, if possible) and it 
should be able to scry as many properties of an object and its 
class as possible at runtime. 

It should certainly require that instance variables are declared, 
because if you need $o->something for runtime-variable somethings, 
you may as well use $o->myhash["something"] instead. Making instance
variables and instance methods fixed, declared properties of a class
enables us to introduce protocols so that we can check for the
presence of a predefined set of instance variables and functions
with a single function call (if (conforms_to($someobj, "protocol")) and
if (conforms_to(someclass, "protocol")) are true, if $someobj or someclass
implement the instance vars and methods which belong to "protocol".)

Proper support for serialization requires that we are able to save
object networks, keeping references intact in order to keep our predefined
data structures. Such serialization greatly simplifies may deeds, such
as building RPC proxies, building generic interface builders, and
other metaprograms. Also, second order serialization would also be
useful, that is, serializing classes, for example by saving and
loading the bytecode of their methods. That enables us to send
not only objects, but even classes over the wire in a RPC call,
or to easily deal with binary-only classes.

All this requires planning and a roadmap, though, and BEFORE any additional
mess is coded up and cast in stone.

 [2000-07-17 12:45 UTC] zeev at cvs dot php dot net
Please keep change requests that would result in changing the entire architecture of PHP on the development mailing list, and not as a feature request here :)
 
PHP Copyright © 2001-2026 The PHP Group
All rights reserved.
Last updated: Mon Jun 15 06:00:02 2026 UTC