Req #42269 [Opn->Csd]: Abstract Classes - "prototyping" not fully allowed
| From: | kevin at metalaxe dot com | Date: | Thu, 01 Dec 2011 00:25:35 +0000 |
| Subject: | Req #42269 [Opn->Csd]: Abstract Classes - "prototyping" not fully allowed | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-165598@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=42269&edit=1
ID: 42269
User updated by: kevin at metalaxe dot com
Reported by: kevin at metalaxe dot com
Summary: Abstract Classes - "prototyping" not fully allowed
-Status: Open
+Status: Closed
Type: Feature/Change Request
-Package: Feature/Change Request
+Package: *General Issues
Operating System: All
PHP Version: 5.2.3
Block user comment: N
Private report: N
New Comment:
I've learned the errors of my ways
Previous Comments:
------------------------------------------------------------------------
[2007-08-11 01:08:05] kevin at metalaxe dot com
Changing to proper version
------------------------------------------------------------------------
[2007-08-11 00:44:30] kevin at metalaxe dot com
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 this bug report at https://bugs.php.net/bug.php?id=42269&edit=1