From:             kevin at metalaxe dot com
Operating system: All
PHP version:      5.2.4RC1
PHP Bug Type:     Feature/Change Request
Bug description:  Abstract Classes -  "prototyping" not fully allowed

Description:
------------
I was working on an interface (abstract class) to implement for kernel
subroutines (that will be singleton classes) in my program/framework and
wanted to define things that needed to be implemented in applicable classes
when I found that I couldn't do everything I needed, or feel I need, to do
in order to prevent "hacking" in extending classes.

I don't expect that these things will be implemented, but it is something
to think about and i feel it would give PHP an edge over many other
languages, if they are not already implemented in them (as some are).

#1 Properties cannot be implemented as abstract
Doing so returns "Fatal error: Properties cannot be declared abstract."
Int he case of a singleton prototype, I'd want to be sure that a property
of the name "instance" was created by the implementing class.

#2 Abstract methods cannot be defined as private
This is a 2 part issue in my opinion. First of all, why can't they be? If
I define a method as abstract and private it means that I want the
implementing class to define that method as private. In the case of this
prototype, I want to ensure that the class in indeed a singleton and cannot
be initiated except though the static method defined later. This brings me
to part 2.

#3 Defining abstract methods as private or protected allows for "weaker"
visibility
This makes defining a prototype class completely useless. If the user is
allowed to ignore my preset visibility and do whatever they want, why would
I ever use abstract to define classes? You don't implement an interface to
"do what you want", you implement an interface to "do what it wants".
Now, on the other hand, and if the prototype allows it (see below), it is
perfectly acceptable to be allowed to extend an implementing class to add
new behavior. This behavior might include overriding the visibility of a
method set in a parent class and assigning it as a weaker alternative.

#4 Abstract methods cannot use the final keyword
As another aside in regards to defining abstract methods this should be
perfectly valid as well if considering prototyping. If I prototype a method
to be final, this means that I want the implementing class to implement
this method as final(NOT that I want the abstract as final, as the error
message seems to imply). Using the above guideline using a declaration like
so:

abstract private final function __construct();

...should mean that the implementing class MUST define that method as so:

private final function __construct(){}

#5 And finally, static methods are not applicable to
abstraction/prototyping
This causes an E_STRICT error of "Strict Standards: Static function
kernel_interface::init() should not be abstract". Again I ask, "Why
shoudn't it be?" By defining a method like so:

abstract public static function &init();

..I am effectively telling the implementing class that it needs to define
the method as:

public static function &init(){}

...which is perfectly acceptable as I want to be sure that, in my case, a
singleton class implements a public, static, method unto which it can be
initiated.

Anyway, sorry for the long report, but I figured it was better than
opening 1 for each example I'd like to see. I'm perfectly happy waiting for
this, but I'd really like to see most of these implemented. I hope that my
example below is enough to deem considerable.

Reproduce code:
---------------
/**
*       Kernel Interface
*
*       An interface class all kernel subroutines implement.
*       All classes implementing this interface are singletons!
**/
abstract class kernel_interface
{
        /**
        *       Instance
        *       Contains loaded this instance
        *
        *       @var            object
        *       @access         private
        **/
        abstract private static $instance = NULL;

        /**
        *       Core
        *       Reference to kernel_core
        *
        *       @var            object
        *       @access         private
        **/
        abstract private $core;

        /**
        *       Construct
        *       Load up the construct. Private for singleton.
        *
        *       @param          object  Reference to kernel_core
        *       @access         private
        */
        abstract private final function __construct( kernel_core &$core );

        /**
        *       INIT
        *       Ensures that only one instance is created
        *
        *       @param          object  Reference to kernel_core
        *       @access         private
        */
        abstract public static final function &init( kernel_core &$core );

        /**
        *       Run
        *       Returns the selected data based on type
        *
        *       @param          array   Array of parameters passed to the 
__call overload in
kernel_core
        *       @return         object  Reference to requested call 
functionality
        *       @access         public
        */
        abstract public final function &run( Array $params );

        /**
        *       Clone
        *       Cloning is disabled for singleton
        *
        *       @access         public
        *       @final
        **/
        public final function __clone()
        {
                trigger_error('Clone is not allowed.', E_USER_ERROR);
        }
}// end interface

//begin implementing class
final class kernel_input_handler extends kernel_interface
{
        /**
        *       Instance
        *       Contains loaded this instance
        *
        *       @var            object
        *       @access         private
        **/
        private static $instance = NULL;

        /**
        *       Core
        *
        *       @var            object
        *       @access         private
        **/
        private $core;

        /**
        *       Construct
        *
        *       @param          object  reference to kernel_core
        *       @access         private
        **/
        private final function __construct( kernel_core &$core )
        {
                $this->core =& $core;

        }

        /**
        *       INIT
        *       Ensures that only one instance of kernel is created
        *
        *       @param          array   Loaded configuration values
        *       @access         private
        **/
        public static final function &init( kernel_core &$core )
        {
                if ( self::$instance === NULL )
                {
                        self::$instance = new self( $core );
                }
                return self::$instance;
        }

        /**
        *       Get
        *       Inititates the selected input class and returns the "gotten" 
data
        *
        *       @param  string  array to get input from
        *       @access         public
        *       @final
        **/
        public final function &run( Array $params )
        {
                # Testing
                return $params;
        }
}

Expected result:
----------------
Explained in description :)

Actual result:
--------------
Explained above :)

-- 
Edit bug report at http://bugs.php.net/?id=42269&edit=1
-- 
Try a CVS snapshot (PHP 4.4): 
http://bugs.php.net/fix.php?id=42269&r=trysnapshot44
Try a CVS snapshot (PHP 5.2): 
http://bugs.php.net/fix.php?id=42269&r=trysnapshot52
Try a CVS snapshot (PHP 6.0): 
http://bugs.php.net/fix.php?id=42269&r=trysnapshot60
Fixed in CVS:                 http://bugs.php.net/fix.php?id=42269&r=fixedcvs
Fixed in release:             
http://bugs.php.net/fix.php?id=42269&r=alreadyfixed
Need backtrace:               http://bugs.php.net/fix.php?id=42269&r=needtrace
Need Reproduce Script:        http://bugs.php.net/fix.php?id=42269&r=needscript
Try newer version:            http://bugs.php.net/fix.php?id=42269&r=oldversion
Not developer issue:          http://bugs.php.net/fix.php?id=42269&r=support
Expected behavior:            http://bugs.php.net/fix.php?id=42269&r=notwrong
Not enough info:              
http://bugs.php.net/fix.php?id=42269&r=notenoughinfo
Submitted twice:              
http://bugs.php.net/fix.php?id=42269&r=submittedtwice
register_globals:             http://bugs.php.net/fix.php?id=42269&r=globals
PHP 3 support discontinued:   http://bugs.php.net/fix.php?id=42269&r=php3
Daylight Savings:             http://bugs.php.net/fix.php?id=42269&r=dst
IIS Stability:                http://bugs.php.net/fix.php?id=42269&r=isapi
Install GNU Sed:              http://bugs.php.net/fix.php?id=42269&r=gnused
Floating point limitations:   http://bugs.php.net/fix.php?id=42269&r=float
No Zend Extensions:           http://bugs.php.net/fix.php?id=42269&r=nozend
MySQL Configuration Error:    http://bugs.php.net/fix.php?id=42269&r=mysqlcfg

Reply via email to