Abstract helper class - php

I have created an helper class:
abstract class Format{
public static function format_array_id_value($result){
$array = [];
foreach($result as $val){
extract($val);
$array[$id] = urldecode($val);
}
return $array;
}
}
I am requiring the containing file at the start of the application. I am attemping to call it from another class method as Format::format_array_id_value($result). I am receiving the error "Fatal error: Class 'Format' not found in Expense.php on line 22".
Am I not thinking about abstract classes correctly? Must I instantiate the class in order to use this helper method?
Thank you. :)

Daniela, there's no reason to use this as an abstract class, it's not its purpose.
As stated in documentation
Classes defined as abstract cannot be instantiated, and any class that contains at least one abstract method must also be abstract. Methods defined as abstract simply declare the method's signature - they cannot define the implementation.
Instead, use a common class
<?php
class FormatHelper
{
public static function formatArrayIdValue($result, $id)
{
$array = [];
foreach ($result as $val) {
extract($val);
$array[$id] = urldecode($val);
}
return $array;
}
}
and make sure you include it in your script:
<?php
require_once('FormatHelper.php');
print_r(
FormatHelper::formatArrayIdValue(['foo bar baz'], 'foo')
);
// output:
// Array ( [foo] => foo bar baz )
And the proper usage of abstract classes is:
<?php
abstract class AbstractFormatHelper
{
// note that abstract method has no body
abstract public static function requiredMethodToBeImplementedInChildClass();
}
class FormatHelper extends AbstractFormatHelper
{
public static function requiredMethodToBeImplementedInChildClass()
{
return 'Implemented!';
}
public static function formatArrayIdValue($result, $id)
{
$array = [];
foreach ($result as $val) {
extract($val);
$array[$id] = urldecode($val);
}
return $array;
}
}
Conclusions & suggestions
Operators
Use :: operator for accessing static methods.
MyClass::myStaticMethod();
Use -> operator for accessing methods of object.
$obj = new MyClass();
$obj->myNonStaticMethod();
Inheritance with abstract
As a Rule of thumb (ROT) abstract class is defined as abstract and contains at least one abstract method. That means that the main purpose of abstract classes is allowing its inheritance,
Although as Jeto pointed as a side effect if the class is defined as abstract, even if it doesn't contain any non_static methods it cannot be instantiated, however, this is not purpose for using abstract classes. Instead, you should use abstract classes only in case when you want to force developers (maybe yourself) for creating methods in their classes which extends your abstract class.
analyse this sample:
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
class MyClass
{
public static function myStaticMethod()
{
return ' this is myStaticMethod()';
}
public function myNonStaticMethod()
{
return 'this is myNonStaticMethod()';
}
}
abstract class AbstractFormatHelper
{
abstract public static function requiredMethodToBeImplementedInChildClass();
abstract protected static function otherProtectedAbstractMethod();
// final abstract protected static function otherProtectedFinalAbstractMethod(); // you even can't declare it
public static function foo()
{
return "foo() doesn't need to be implemented";
}
protected static function bar()
{
return "this doesn't need to be implemented but will be not accessible if you won't change it to public";
}
final protected static function baz()
{
return "baz() is final PROTECTED, you can NOT override it in the child, but you still can access it in child by getter ";
}
final private static function boo()
{
return 'boo() is final PRIVATE but and you can NOT access it in child by getter ';
}
}
class FormatHelper extends AbstractFormatHelper
{
public static function requiredMethodToBeImplementedInChildClass()
{
return 'Implemented!';
}
public static function otherProtectedAbstractMethod()
{
return 'erProtectedAbstractMethod() implemented';
}
public static function foo()
{
return parent::foo() . " but foo() can be implemented";
}
public static function bar()
{
return 'method bar() which was protected now can be public OR protected NOT private (see below)';
}
// That wouldn't work with private
// private static function bar()
// {
// return parent::bar() . ' I wanted to override it in child as a private but it is impossible';
// }
public static function getBaz()
{
return self::baz(); // you can still access it in child class, cause is protected
}
// public static function getBoo()
// {
// return self::boo(); // it won't work ass parent boo is private
// }
}
echo '<pre> OPERATORS' . PHP_EOL . PHP_EOL;
// operands
echo MyClass::myStaticMethod() . PHP_EOL;
echo MyClass::myNonStaticMethod() . PHP_EOL; // Warning In PHP 7, calling non-static methods statically is deprecated
$obj = new MyClass();
echo $obj->myStaticMethod() . PHP_EOL; // wouldn't use that
echo $obj::myStaticMethod() . PHP_EOL;
echo $obj->myNonStaticMethod() . PHP_EOL;
echo $obj::myNonStaticMethod() . PHP_EOL; // Warning In PHP 7, calling non-static methods statically is deprecated
echo PHP_EOL . PHP_EOL;
echo 'INHERITANCE WITH `abstract`' . PHP_EOL . PHP_EOL;
echo FormatHelper::foo() . PHP_EOL;
echo FormatHelper::bar() . PHP_EOL;
// echo FormatHelper::baz() . PHP_EOL; // you cannot access it as it's protected and final
echo FormatHelper::getBaz() . PHP_EOL;
Namespaces
Although this tip exceeds boundaries of this answer consider using namespaces in the future, especially, when your project will grow, so with proper autoload you will be able to use classes without requiring them each time like.
<?php
require_once('autoloader.php');
print_r(\Your\Namespace\FormatHelper::formatArrayIdValue(['foo bar baz'], 'foo');
print_r(\Other\Namespace\OtherHelper::format('foo');
print_r(\Quite\Other\Something\SomeHelper::someMethod());
Conventions
note, for the convention I renamed the classes and methods names, also added $id param as it was missing.

In the end, I figured the autoloader was not configured correctly, thus not loading the abstract Format class. Although I am still uncertain why manually requiring this file did not work, fixing the autoloader did solve it. Now onto the next set of errors.
Thank you lads for all of your input. :)

Related

How to implement abstract properties in PHP? [duplicate]

Is there any way to define abstract class properties in PHP?
abstract class Foo_Abstract {
abstract public $tablename;
}
class Foo extends Foo_Abstract {
//Foo must 'implement' $property
public $tablename = 'users';
}
There is no such thing as defining a property.
You can only declare properties because they are containers of data reserved in memory on initialization.
A function on the other hand can be declared (types, name, parameters) without being defined (function body missing) and thus, can be made abstract.
"Abstract" only indicates that something was declared but not defined and therefore before using it, you need to define it or it becomes useless.
No, there is no way to enforce that with the compiler, you'd have to use run-time checks (say, in the constructor) for the $tablename variable, e.g.:
class Foo_Abstract {
public final function __construct(/*whatever*/) {
if(!isset($this->tablename))
throw new LogicException(get_class($this) . ' must have a $tablename');
}
}
To enforce this for all derived classes of Foo_Abstract you would have to make Foo_Abstract's constructor final, preventing overriding.
You could declare an abstract getter instead:
abstract class Foo_Abstract {
abstract public function get_tablename();
}
class Foo extends Foo_Abstract {
protected $tablename = 'tablename';
public function get_tablename() {
return $this->tablename;
}
}
Depending on the context of the property, if I want to force declaration of an abstract class property in an extended class, I like to use a constant with the static keyword for the property in the abstract object constructor or setter/getter methods. You can optionally use final to prevent the method from being overridden in extended classes.
Example: https://3v4l.org/WH5Xl
abstract class AbstractFoo
{
public $bar;
final public function __construct()
{
$this->bar = static::BAR;
}
}
class Foo extends AbstractFoo
{
//const BAR = 'foobar'; //uncomment to prevent exception
}
$foo = new Foo();
//Fatal Error: Undefined class constant 'BAR'
However, the extended class overrides the parent class properties and methods if redefined.
For example; if a property is declared as protected in the parent and redefined as public in the extended class, the resulting property is public. Otherwise, if the property is declared private in the parent it will remain private and not available to the extended class.
http://www.php.net//manual/en/language.oop5.static.php
As stated above, there is no such exact definition.
I, however, use this simple workaround to force the child class to define the "abstract" property:
abstract class Father
{
public $name;
abstract protected function setName(); // now every child class must declare this
// function and thus declare the property
public function __construct()
{
$this->setName();
}
}
class Son extends Father
{
protected function setName()
{
$this->name = "son";
}
function __construct(){
parent::__construct();
}
}
The need for abstract properties can indicate design problems. While many of answers implement kind of Template method pattern and it works, it always looks kind of strange.
Let's take a look at the original example:
abstract class Foo_Abstract {
abstract public $tablename;
}
class Foo extends Foo_Abstract {
//Foo must 'implement' $property
public $tablename = 'users';
}
To mark something abstract is to indicate it a must-have thing. Well, a must-have value (in this case) is a required dependency, so it should be passed to the constructor during instantiation:
class Table
{
private $name;
public function __construct(string $name)
{
$this->name = $name;
}
public function name(): string
{
return $this->name;
}
}
Then if you actually want a more concrete named class you can inherit like so:
final class UsersTable extends Table
{
public function __construct()
{
parent::__construct('users');
}
}
This can be useful if you use DI container and have to pass different tables for different objects.
I've asked myself the same question today, and I'd like to add my two cents.
The reason we would like abstract properties is to make sure that subclasses define them and throw exceptions when they don't. In my specific case, I needed something that could work with statically.
Ideally I would like something like this:
abstract class A {
abstract protected static $prop;
}
class B extends A {
protected static $prop = 'B prop'; // $prop defined, B loads successfully
}
class C extends A {
// throws an exception when loading C for the first time because $prop
// is not defined.
}
I ended up with this implementation
abstract class A
{
// no $prop definition in A!
public static final function getProp()
{
return static::$prop;
}
}
class B extends A
{
protected static $prop = 'B prop';
}
class C extends A
{
}
As you can see, in A I don't define $prop, but I use it in a static getter. Therefore, the following code works
B::getProp();
// => 'B prop'
$b = new B();
$b->getProp();
// => 'B prop'
In C, on the other hand, I don't define $prop, so I get exceptions:
C::getProp();
// => Exception!
$c = new C();
$c->getProp();
// => Exception!
I must call the getProp() method to get the exception and I can't get it on class loading, but it is quite close to the desired behavior, at least in my case.
I define getProp() as final to avoid that some smart guy (aka myself in 6 months) is tempted to do
class D extends A {
public static function getProp() {
// really smart
}
}
D::getProp();
// => no exception...
As you could have found out by just testing your code:
Fatal error: Properties cannot be declared abstract in ... on line 3
No, there is not. Properties cannot be declared abstract in PHP.
However you can implement a getter/setter function abstract, this might be what you're looking for.
Properties aren't implemented (especially public properties), they just exist (or not):
$foo = new Foo;
$foo->publicProperty = 'Bar';
PHP 7 makes it quite a bit easier for making abstract "properties". Just as above, you will make them by creating abstract functions, but with PHP 7 you can define the return type for that function, which makes things a lot easier when you're building a base class that anyone can extend.
<?php
abstract class FooBase {
abstract public function FooProp(): string;
abstract public function BarProp(): BarClass;
public function foo() {
return $this->FooProp();
}
public function bar() {
return $this->BarProp()->name();
}
}
class BarClass {
public function name() {
return 'Bar!';
}
}
class FooClass extends FooBase {
public function FooProp(): string {
return 'Foo!';
}
public function BarProp(): BarClass {
// This would not work:
// return 'not working';
// But this will!
return new BarClass();
}
}
$test = new FooClass();
echo $test->foo() . PHP_EOL;
echo $test->bar() . PHP_EOL;
if tablename value will never change during the object's lifetime, following will be a simple yet safe implementation.
abstract class Foo_Abstract {
abstract protected function getTablename();
public function showTableName()
{
echo 'my table name is '.$this->getTablename();
}
}
class Foo extends Foo_Abstract {
//Foo must 'implement' getTablename()
protected function getTablename()
{
return 'users';
}
}
the key here is that the string value 'users' is specified and returned directly in getTablename() in child class implementation. The function mimics a "readonly" property.
This is fairly similar to a solution posted earlier on which uses an additional variable. I also like Marco's solution though it can be a bit more complicated.
Just define the property in the base class without assigning it a (default) value.
Getting the property value without redefining it with a default value or assigning it a value will throw an Error.
<?php
class Base {
protected string $name;
public function i_am() : string {
return $this->name;
}
}
class Wrong extends Base {
...
}
class Good extends Base {
protected string $name = 'Somebody';
}
$test = new Good();
echo $test->i_am(), '<br>'; // Will show "Nobody"
$test = new Wrong();
echo $test->i_am(), '<br>'; // Will throw an Error:
// Error: Typed property Base::$name must not be accessed before initialization in ....
?>
You can define a static property in an abstract class.
<?php
abstract class Foo {
private static $bar = "1234";
public static function func() {
echo self::$bar;
}
}
Foo::func(); // It will be printed 1234
Too late to answer the question, but you may use the difference between self and static as follows
<?php
class A { // Base Class
protected static $name = 'ClassA';
public static function getSelfName() {
return self::$name;
}
public static function getStaticName() {
return static::$name;
}
}
class B extends A {
protected static $name = 'ClassB';
}
echo A::getSelfName(); // ClassA
echo A::getStaticName(); // ClassA
echo B::getSelfName(); // ClassA
echo B::getStaticName(); // ClassB

Constructor can access parent private properties in PHP?

When dealing with inheritance in PHP I found some lack of knowledge, mainly about constructors and private properties.
Let's take this code as example:
<?php
class Module
{
public $type;
public function __construct($type)
{
$this->type = $type;
}
}
class BModule extends Module
{
}
class CModule extends BModule
{
}
class A
{
private $module;
public function __construct(Module $module)
{
echo 'Set module for '.__CLASS__.' to '.$module->type . PHP_EOL;
echo "<br>";
$this->module = $module;
}
public function getModule()
{
echo "I (as " . __CLASS__ . ") have a module of type " . $this->module->type;
return $this->module->type;
}
}
class B extends A
{
}
$m = new Module('base-module');
$bm = new BModule('bi-module');
echo "<br>--------A---------<br>";
$a = new A($m);
echo "<br>A is of type " . $a->getModule();
echo "<br>--------B---------<br>";
$b = new B($bm);
echo "<br>B is of type " . $b->getModule();
Some questions:
shouldn't B construction call the constructor in the context of B? (and so I would expect it to fail cause it didn't inherited the private property $module)
or PHP would simply call the A constructor, using/referencing methods and properties from A? (including the private ones)
I can pass to $b either a Module or a BModule object; this is because BModule is a child of Module. Is PHP checking some inheritance chain (checking the parents) of the passed object when verifying the type hinting?
so can I pass to the constructor either an object of type Module or BModule or CModule?
And this is another example:
<?php
class a
{
private $a;
protected $a_copy;
public function __construct($a_value)
{
$this->a = $a_value;
$this->a_copy = $this->a;
}
public function getA()
{
return $this->a;
}
public function getCopyA()
{
return $this->a;
}
}
class b extends a
{
}
$a = new a('value for a');
$b = new b('value for b');
echo "<br>-----A-----<br>";
echo $a->getA()."<br>";
echo $a->getCopyA()."<br>";
echo "<br>-----B-----<br>";
echo $b->getA()." (I would expect to have no access to \$a)<br>";
echo $b->getCopyA()."<br>";
Being the property $a private, I would expect to not be able to access it or do anything with it from the class b.
It is a little bit non-sense for my actual understanding.
This is expected functionality, although B inherits all of the methods of A, they're not called in the context of B, they're called in the context of A. So the A constructor is called. This means that functions defined in A can access A's properties even when the object is extended. Methods defined in A cannot access properties of B however, which appears to be your understanding.
So to shortly answer your questions:
No, functions are always called in the context of where they are defined, not from where they are called.
PHP will check all the way down the inheritance chain to see if it's correct. Any child of a Class can be assumed to have the same functions. So if B extends A, You can use either B or A as a parameter when it's type-hinted to A, but only use B if it's type-hinted to B
Ad 1: No, the context of the called method is where the method (in this case the constructor) is declared. If the context would be class B then anyone could break your class simply by extending it.
Take a look at this example:
class A
{
private $module;
public function __construct(Module $module)
{
echo 'Set module for '.__CLASS__.' to '.$module->type . PHP_EOL;
echo "<br>";
$this->module = $module;
}
}
class B extends A
{
public function __construct()
{
parent::__construct(new Module()); // call the parent (which is A)
}
}
This illustrates how the scope of A::__construct() is actually the A class.
Ad 2: Yes, each object that is an instance of sub class can be used in place of the super class. This is why you should write your classes so that they can be substituted when the static typing requires a super class. For more information on this subject see the Liskov substitution principle.
As for the last example: again there is no code in sub class that would operate on private members of the super class. All code operates from within the super class context. So there is no problem here.
There would be a problem if you tried to overload methods of super class and use its private members like this:
class b extends a
{
public function getA()
{
return $this->a . "_suffix"; // error
}
}
In such case you must depend on the implementation of getA() method in the super class:
class b extends a
{
public function getA()
{
return parent::getA() . "_suffix"; // ok, we are depending on the super class implementation
}
}

PHP: access a parent's static variable from an extended class' method

Still trying to figure out oop in PHP5. The question is, how to access a parent's static variable from an extended class' method. Example below.
<?php
error_reporting(E_ALL);
class config {
public static $base_url = 'http://example.moo';
}
class dostuff extends config {
public static function get_url(){
echo $base_url;
}
}
dostuff::get_url();
?>
I thought this would work from experience in other languages.
It's completely irrelevant that the property is declared in the parent, you access it the way you access any static property:
self::$base_url
or
static::$base_url // for late static binding
Yes, it's possible, but actually should be written like this:
class dostuff extends config {
public static function get_url(){
echo parent::$base_url;
}
}
But in this case you can access it both with self::$base_url and static::$base_url - as you don't redeclare this property in the extending class. Have you done it so, there would have been a distinction:
self::$base_url would always refer to the property in the same class that line's written,
static::$base_url to the property of the class the object belongs to (so called 'late static binding').
Consider this example:
class config {
public static $base_url = 'http://config.example.com';
public function get_self_url() {
return self::$base_url;
}
public function get_static_url() {
return static::$base_url;
}
}
class dostuff extends config {
public static $base_url = 'http://dostuff.example.com';
}
$a = new config();
echo $a->get_self_url(), PHP_EOL;
echo $a->get_static_url(), PHP_EOL; // both config.example.com
$b = new dostuff();
echo $b->get_self_url(), PHP_EOL; // config.example.com
echo $b->get_static_url(), PHP_EOL; // dostuff.example.com

PHP abstract properties

Is there any way to define abstract class properties in PHP?
abstract class Foo_Abstract {
abstract public $tablename;
}
class Foo extends Foo_Abstract {
//Foo must 'implement' $property
public $tablename = 'users';
}
There is no such thing as defining a property.
You can only declare properties because they are containers of data reserved in memory on initialization.
A function on the other hand can be declared (types, name, parameters) without being defined (function body missing) and thus, can be made abstract.
"Abstract" only indicates that something was declared but not defined and therefore before using it, you need to define it or it becomes useless.
No, there is no way to enforce that with the compiler, you'd have to use run-time checks (say, in the constructor) for the $tablename variable, e.g.:
class Foo_Abstract {
public final function __construct(/*whatever*/) {
if(!isset($this->tablename))
throw new LogicException(get_class($this) . ' must have a $tablename');
}
}
To enforce this for all derived classes of Foo_Abstract you would have to make Foo_Abstract's constructor final, preventing overriding.
You could declare an abstract getter instead:
abstract class Foo_Abstract {
abstract public function get_tablename();
}
class Foo extends Foo_Abstract {
protected $tablename = 'tablename';
public function get_tablename() {
return $this->tablename;
}
}
Depending on the context of the property, if I want to force declaration of an abstract class property in an extended class, I like to use a constant with the static keyword for the property in the abstract object constructor or setter/getter methods. You can optionally use final to prevent the method from being overridden in extended classes.
Example: https://3v4l.org/WH5Xl
abstract class AbstractFoo
{
public $bar;
final public function __construct()
{
$this->bar = static::BAR;
}
}
class Foo extends AbstractFoo
{
//const BAR = 'foobar'; //uncomment to prevent exception
}
$foo = new Foo();
//Fatal Error: Undefined class constant 'BAR'
However, the extended class overrides the parent class properties and methods if redefined.
For example; if a property is declared as protected in the parent and redefined as public in the extended class, the resulting property is public. Otherwise, if the property is declared private in the parent it will remain private and not available to the extended class.
http://www.php.net//manual/en/language.oop5.static.php
As stated above, there is no such exact definition.
I, however, use this simple workaround to force the child class to define the "abstract" property:
abstract class Father
{
public $name;
abstract protected function setName(); // now every child class must declare this
// function and thus declare the property
public function __construct()
{
$this->setName();
}
}
class Son extends Father
{
protected function setName()
{
$this->name = "son";
}
function __construct(){
parent::__construct();
}
}
The need for abstract properties can indicate design problems. While many of answers implement kind of Template method pattern and it works, it always looks kind of strange.
Let's take a look at the original example:
abstract class Foo_Abstract {
abstract public $tablename;
}
class Foo extends Foo_Abstract {
//Foo must 'implement' $property
public $tablename = 'users';
}
To mark something abstract is to indicate it a must-have thing. Well, a must-have value (in this case) is a required dependency, so it should be passed to the constructor during instantiation:
class Table
{
private $name;
public function __construct(string $name)
{
$this->name = $name;
}
public function name(): string
{
return $this->name;
}
}
Then if you actually want a more concrete named class you can inherit like so:
final class UsersTable extends Table
{
public function __construct()
{
parent::__construct('users');
}
}
This can be useful if you use DI container and have to pass different tables for different objects.
I've asked myself the same question today, and I'd like to add my two cents.
The reason we would like abstract properties is to make sure that subclasses define them and throw exceptions when they don't. In my specific case, I needed something that could work with statically.
Ideally I would like something like this:
abstract class A {
abstract protected static $prop;
}
class B extends A {
protected static $prop = 'B prop'; // $prop defined, B loads successfully
}
class C extends A {
// throws an exception when loading C for the first time because $prop
// is not defined.
}
I ended up with this implementation
abstract class A
{
// no $prop definition in A!
public static final function getProp()
{
return static::$prop;
}
}
class B extends A
{
protected static $prop = 'B prop';
}
class C extends A
{
}
As you can see, in A I don't define $prop, but I use it in a static getter. Therefore, the following code works
B::getProp();
// => 'B prop'
$b = new B();
$b->getProp();
// => 'B prop'
In C, on the other hand, I don't define $prop, so I get exceptions:
C::getProp();
// => Exception!
$c = new C();
$c->getProp();
// => Exception!
I must call the getProp() method to get the exception and I can't get it on class loading, but it is quite close to the desired behavior, at least in my case.
I define getProp() as final to avoid that some smart guy (aka myself in 6 months) is tempted to do
class D extends A {
public static function getProp() {
// really smart
}
}
D::getProp();
// => no exception...
As you could have found out by just testing your code:
Fatal error: Properties cannot be declared abstract in ... on line 3
No, there is not. Properties cannot be declared abstract in PHP.
However you can implement a getter/setter function abstract, this might be what you're looking for.
Properties aren't implemented (especially public properties), they just exist (or not):
$foo = new Foo;
$foo->publicProperty = 'Bar';
PHP 7 makes it quite a bit easier for making abstract "properties". Just as above, you will make them by creating abstract functions, but with PHP 7 you can define the return type for that function, which makes things a lot easier when you're building a base class that anyone can extend.
<?php
abstract class FooBase {
abstract public function FooProp(): string;
abstract public function BarProp(): BarClass;
public function foo() {
return $this->FooProp();
}
public function bar() {
return $this->BarProp()->name();
}
}
class BarClass {
public function name() {
return 'Bar!';
}
}
class FooClass extends FooBase {
public function FooProp(): string {
return 'Foo!';
}
public function BarProp(): BarClass {
// This would not work:
// return 'not working';
// But this will!
return new BarClass();
}
}
$test = new FooClass();
echo $test->foo() . PHP_EOL;
echo $test->bar() . PHP_EOL;
if tablename value will never change during the object's lifetime, following will be a simple yet safe implementation.
abstract class Foo_Abstract {
abstract protected function getTablename();
public function showTableName()
{
echo 'my table name is '.$this->getTablename();
}
}
class Foo extends Foo_Abstract {
//Foo must 'implement' getTablename()
protected function getTablename()
{
return 'users';
}
}
the key here is that the string value 'users' is specified and returned directly in getTablename() in child class implementation. The function mimics a "readonly" property.
This is fairly similar to a solution posted earlier on which uses an additional variable. I also like Marco's solution though it can be a bit more complicated.
Just define the property in the base class without assigning it a (default) value.
Getting the property value without redefining it with a default value or assigning it a value will throw an Error.
<?php
class Base {
protected string $name;
public function i_am() : string {
return $this->name;
}
}
class Wrong extends Base {
...
}
class Good extends Base {
protected string $name = 'Somebody';
}
$test = new Good();
echo $test->i_am(), '<br>'; // Will show "Nobody"
$test = new Wrong();
echo $test->i_am(), '<br>'; // Will throw an Error:
// Error: Typed property Base::$name must not be accessed before initialization in ....
?>
You can define a static property in an abstract class.
<?php
abstract class Foo {
private static $bar = "1234";
public static function func() {
echo self::$bar;
}
}
Foo::func(); // It will be printed 1234
Too late to answer the question, but you may use the difference between self and static as follows
<?php
class A { // Base Class
protected static $name = 'ClassA';
public static function getSelfName() {
return self::$name;
}
public static function getStaticName() {
return static::$name;
}
}
class B extends A {
protected static $name = 'ClassB';
}
echo A::getSelfName(); // ClassA
echo A::getStaticName(); // ClassA
echo B::getSelfName(); // ClassA
echo B::getStaticName(); // ClassB

Faking Late Static Binding before php 5.3

I need an inherited static function "call" to call another static function "inner" that has been overridden. I could do this with late static binding, but my host does not have php5.3 yet and so I need to work around it.
class ClassA{
static function call()
{
return self::inner();
}
static function inner(){
return "Class A";
}
}
class ClassB extends ClassA{
static function inner(){
return "Class B";
}
}
echo "<p>Class A = " . ClassA::call();
echo "<p>Class B = " . ClassB::call();
I would like the output to be:
Class A = Class A
Class B = Class B
But what it is:
Class A = Class A
Class B = Class A
My gut tells me that I should be able to write something in call() to detect what object was referenced when "call()" was, well, called. So instead of self::inner() it would so something along the lines of calledclass::inner(). Detecting the proper version of inner() to call from the original method call.
If performance is not an issue, you can use debug_backtrace() to find the called class:
$bt = debug_backtrace();
return get_class($bt[1]['object']);
http://php.net/manual/en/function.debug-backtrace.php
You can use object instances rather than classes. If you want a global symbol, you can use a global variable. Since they are rather unwieldy in PHP, one trick is to wrap it in a function. Eg.:
class ClassA {
function call() {
return $this->inner();
}
function inner() {
return "Class A";
}
}
function ClassA() {
static $instance;
return $instance ? $instance : new ClassA();
}
class ClassB extends ClassA {
function inner() {
return "Class B";
}
}
function ClassB() {
static $instance;
return $instance ? $instance : new ClassB();
}
echo "<p>Class A = " . ClassA()->call();
echo "<p>Class B = " . ClassB()->call();
But a better idea might be to avoid global symbols altogether; The reason why it works well in Ruby/Rails, is that Ruby doesn't really have static state in the same way that PHP has. A class can be rebound and added to at runtime, which allows for easy extension of the framework. In PHP, classes are always final, so referring to them in application code, is a very strong degree of coupling.
Unfortunately there is no nice way to do it (otherwise PHPers wouldn't cheer so much for that feature).
You have to pass class name. PHP < 5.3 also doesn't have nice syntax for static calls with dynamic class name which makes whole thing even uglier:
static function call($class)
{
return call_user_func(array($class,"inner"));
}
…
ClassA::call("ClassA");
ClassB::call("ClassB");
If you can change the code (and not use static), then singletons make it more bearable. You can make helper function to ease the syntax:
X("ClassA")->call();
X("ClassB")->call();
The X function should look up, create and return instance of a class.
Often, late static binding is needed when a child calls back a method of the parent who, in turn, calls an abstract static method of the child. I was in such a postition, and could not use static:: as my PHP was not version 5.3 (or later). The following accomplished late static binding by way of debug_backtrace().
abstract class ParentClass
{
static function parent_method()
{
$child_class_str = self::get_child_class();
eval("\$r = ".$child_class_str."::abstract_static();");
return $r;
}// CHILD MUST OVERRIDE TO PUT ITSELF INTO TRACE
protected abstract static function abstract_static(); // THIS NEEDS LATE STATIC BINDING
private static function get_child_class()
{
$backtrace = debug_backtrace();
$num = count($backtrace);
for($i = 0; $i < $num; $i++)
{
if($backtrace[$i]["class"] !== __CLASS__)
return $backtrace[$i]["class"];
}
return null;
}
}
class ChildClass extends ParentClass
{
static function parent_method(){ return parent::parent_method(); }
protected static function abstract_static()
{
return __METHOD__."()";
}// From ParentClass
}
print "The call was: ". ChildClass::parent_method();
Here's a quick example.
<?php
class ClassA{
public function call(){
return $this->inner();
}
static function inner(){
return "Class A";
}
static function init($class){
return new $class();
}
}
class ClassB extends ClassA{
static function inner(){
return "Class B";
}
}
echo "<p>Class A = " . ClassA::init("ClassA")->call();
echo "<p>Class B = " . ClassB::init("ClassB")->call();
?>
If you don't like passing in the class name you could add a static init function to the child class and explicitly pass it there as well. This would allow you to do something like: ClassA::init()->call() and ClassB::init()->call() but would have some minor code duplication.
Since you cant use static:: , or get_called_class(), or __callStatic,
you'll have to call the inner() function with some indication with
the called class (as mentioned in the other answers). An instance
of the called class would be fine.
You can add "Pseudo Static" methods to mimick every static method
you need to overwrite. This doubles your code, but
by doing this as below, I hope the code is easier to upgrade once
php5.3 comes around: just remove all the ps methods and all the
functions referencing them (and change "self" to "static" where needed ..)
class ClassA{
static function call()
{
return self::inner();
}
static function inner(){
return "Class A";
}
public function _ps_call()
{
return $this->_ps_inner();
}
}
class ClassB extends ClassA{
public static function getInstance()
{
return new self();
}
public static function call()
{
return self::getInstance()->_ps_call();
}
static function inner()
{
return "Class B";
}
public function _ps_inner()
{
return self::inner();
}
}
echo "<p>Class A = " . ClassA::call();
echo "<p>Class B = " . ClassB::call();

Categories