In PHP, if a static attribute is defined in the parent class, it cannot be overridden in a child class. But I'm wondering if there's any way around this.
I'm trying to write a wrapper for someone else's (somewhat clunky) function. The function in question can be applied to lots of different data types but requires different flags and options for each. But 99% of the time, a default for each type would suffice.
It would be nice if this could be done with inheritance, without having to write new functions each time. For example:
class Foo {
public static $default = 'DEFAULT';
public static function doSomething ($param = FALSE ) {
$param = ($param === FALSE) ? self::$default : $param;
return $param;
}
}
class Bar extends Foo {
public static $default = 'NEW DEFAULT FOR CHILD CLASS';
}
echo Foo::doSomething() . "\n";
// echoes 'DEFAULT'
echo Bar::doSomething() . "\n";
// echoes 'DEFAULT' not 'NEW DEFAULT FOR CHILD CLASS'
// because it references $default in the parent class :(
Actually I think it is not true: you can ovverride static propeties (you need >=5.3 PHP for that). But you have to be careful when refrencing for that static property (and this is the mistake in the original code)
You need to use static::$myStaticProperty instead of using self::$myStaticProperty
self:: will refrence to the current class so if you are inside an inherited static method this will refrence the static property of that class defined that method! While using reference keyword static:: will act like $this - when you are using instance methods/propeties.
doSomething() is an inherited static method in class Bar in your example. Since you used self:: there, it will reference to the static property of class Foo. This is the reason why you didn't see any difference... Try to change self:: to static::!
Here is a code example - I used it myself to test those things. We have static property/method inheritance, override and value change in it - run it and you will see the result!
class A {
// a static property - we will test override with it
protected static $var = 'class A var - override';
// a static property - we will test value overwrite with it
protected static $var2 = 'class A var2 - value overwrite';
public static function myStaticOverridePropertyTest() {
return static::$var;
}
public static function myStaticValueOverwritePropertyTest() {
return static::$var2;
}
/**
* This method is defined only here - class B will inherit this one!
* We use it to test the difference btw self:: and static::
*
* #return string
*/
public static function myStaticMethodTest() {
//return self::getValue();
return static::getValue();
}
/**
* This method will be overwritten in class B
* #return string
*/
protected static function getValue() {
return 'value from class A';
}
}
class B extends A {
// we override this inherited static property
protected static $var = 'class B var - override';
/**
* This method is overwritten from class A
* #return string
*/
protected static function getValue() {
return 'value from class B';
}
/**
* We modify the value of the inherited $var2 static property
*/
public static function modStaticProperty() {
self::$var2 = 'class B - altered value! - value overwrite';
}
}
echo ("-- testing class A:\n");
echo (A::myStaticOverridePropertyTest(). "\n");
echo (A::myStaticValueOverwritePropertyTest(). "\n");
echo (A::myStaticMethodTest(). "\n");
echo ("-- now testing class B:\n");
echo (B::myStaticOverridePropertyTest(). "\n");
echo (B::myStaticValueOverwritePropertyTest(). "\n");
echo (" now invoking B::modStaticProperty() .\n");
B::modStaticProperty();
echo (B::myStaticValueOverwritePropertyTest(). "\n");
echo ("-- now re-testing class A:\n");
echo (A::myStaticOverridePropertyTest(). "\n");
echo (A::myStaticValueOverwritePropertyTest(). "\n");
echo (A::myStaticMethodTest(). "\n");
This will output:
-- testing class A:
class A var - override
class A var2 - value overwrite
value from class A
-- now testing class B:
class B var - override
class A var2 - value overwrite
now invoking B::modStaticProperty() ...
class B - altered value! - value overwrite
-- now re-testing class A:
class A var - override
class B - altered value! - value overwrite
value from class A
And here we are, you can see the difference between overriden and only value overwritten static properties... look the output line I marked with bold! When we invoked the modStaticProperty() of class B, it changed the value of that static variable in class A too. Since that static property was inherited and was not overriden! Think about it...
The forthcoming PHP 5.3.0 release includes late static binding, which might help. Using this feature you could use a static variable inside a static method, and let the late static binding take care of finding the "right" method.
class Foo {
public static function getDefault() {
static $default = 'DEFAULT';
return $default;
}
public static function doSomething ($param) {
$default=static::getDefault(); // here is the late static binding
$param = ($param === FALSE) ? $default : $param;
return $param;
}
}
class Bar extends Foo {
public static function getDefault() {
static $default = 'NEW DEFAULT FOR CHILD CLASS';
return $default;
}
}
Classic example of why using statics as globals (functions in this case) is a bad idea no matter the language.
The most robust method is to create multiple implementation sub classes of an abstract base "Action" class.
Then to try and remove some of the annoyance of instantiating an instance of the class just to call it's methods, you can wrap it in a factory of some sort.
For example:
abstract class AbstractAction {
public abstract function do();
}
class FooAction extends AbstractAction {
public function do() {
echo "Do Foo Action";
}
}
class BarAction extends AbstractAction {
public function do() {
echo "Do Bar Action";
}
}
Then create a factory to "aid" in instantiation of the function
class ActionFactory {
public static function get($action_name) {
//... return AbstractAction instance here
}
}
Then use it as:
ActionFactory::get('foo')->do();
Related
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
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
}
}
I found something strange in the process of PHP object inheritance.
I can call NON static parent method from a subclass.
I cannot find any information about the possibility of this happening. Moreover, the PHP interpreter does not display errors.
Why it is possible?
Is this normal PHP feature?
Is it bad practice?
Here you are a code that you can use to test it.
<?php
class SomeParent {
// we will initialize this variable right here
private $greeting = 'Hello';
// we will initialize this in the constructor
private $bye ;
public function __construct()
{
$this->bye = 'Goodbye';
}
public function sayHi()
{
print $this->greeting;
}
public function sayBye()
{
print $this->bye;
}
public static function saySomething()
{
print 'How are you?';
}
}
class SomeChild extends SomeParent {
public function __construct()
{
parent::__construct();
}
/**
* Let's see what happens when we call a parent method
* from an overloaded method of its child
*/
public function sayHi()
{
parent::sayHi();
}
/**
* Let's call a parent method from an overloaded method of
* its child. But this time we will try to see if it will
* work for parent properties that were initialized in the
* parent's constructor
*/
public function sayBye()
{
parent::sayBye();
}
/**
* Let's see if calling static methods on the parent works
* from an overloaded static method of its child.
*/
public static function saySomething()
{
parent::saySomething();
}
}
$obj = new SomeChild();
$obj->sayHi(); // prints Hello
$obj->sayBye(); // prints Goodbye
SomeChild::saySomething(); // prints How are you?
That's the way, methods of a parent class are called from subclasses in PHP. If you override a method, you often need a way to include the functionality of the parent's method. PHP provides this via the parent keyword. See http://www.php.net/manual/en/keyword.parent.php.
This is a default functionality of PHP, In this way even after overriding the parent method, you can still add its existing functionality in child method.
ex-
class vehicle {
function horn()
{
echo "poo poo";
}
}
class audi extends vehicle {
function horn()
{
parent::horn();
echo "pee pee";
}
}
$newvehicle =new audi();
$newvehicle->horn(); // this will print out "poo poo pee pee"
What is the difference between using self and static in the example below?
class Foo
{
protected static $bar = 1234;
public static function instance()
{
echo self::$bar;
echo "\n";
echo static::$bar;
}
}
Foo::instance();
produces
1234
1234
When you use self to refer to a class member, you're referring to the class within which you use the keyword. In this case, your Foo class defines a protected static property called $bar. When you use self in the Foo class to refer to the property, you're referencing the same class.
Therefore if you tried to use self::$bar elsewhere in your Foo class but you had a Bar class with a different value for the property, it would use Foo::$bar instead of Bar::$bar, which may not be what you intend:
class Foo
{
protected static $bar = 1234;
}
class Bar extends Foo
{
protected static $bar = 4321;
}
When you call a method via static, you're invoking a feature called late static bindings (introduced in PHP 5.3).
In the above scenario, using self will result in Foo::$bar(1234).
And using static will result in Bar::$bar (4321) because with static, the interpreter takes into account the redeclaration within the Bar class during runtime.
// self
var_dump(Foo::$bar);
// (int) 1234
// static
var_dump(Bar::$bar);
// (int) 4321
You typically use late static bindings for methods or even the class itself, rather than properties, as you don't often redeclare properties in subclasses; an example of using the static keyword for invoking a late-bound constructor can be found in this related question: New self vs. new static
However, that doesn't preclude using static with properties as well.
I have small example showing difference between self and static. Using static:: performs Late Static Binding and thus it binds the variable value from child class.
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
With self call:
class Phone
{
protected static $number = 123;
public function getNumber()
{
return self::$number;
}
}
class Fax extends Phone
{
protected static $number = 234;
}
// Displays: "123"
echo (new Fax)->getNumber();
You can see above, even though we have overridden the $number with our Fax class, getNumber() still returns 123.
This because we have asked PHP to give us the variable where it was defined in -- which will return Phones variable instead.
If we swap the self call with static, we will get Faxs overridden value instead:
With static call:
class Phone
{
protected static $number = 123;
public function getNumber()
{
// return self::$number;
return static::$number;
}
}
class Fax extends Phone
{
protected static $number = 234;
}
// Displays: "234"
echo (new Fax)->getNumber();
As mentioned one of the main differences is that static allows for late static bindings. One of the most useful scenarios that I found was for creating Base classes for Singleton Classes:
class A { // Base Class
protected static $name = '';
protected static function getName() {
return static::$name;
}
}
class B extends A {
protected static $name = 'MyCustomNameB';
}
class C extends A {
protected static $name = 'MyCustomNameC';
}
echo B::getName(); // MyCustomNameB
echo C::getName(); // MyCustomNameC
Using return static::$name in the Base class will return what was statically attached when it was extended. If you were to use return self::$name then B::getName() would return an empty string as that is what is declared in the Base class.
Maybe this self-explained code helps you:
class Foo
{
protected static $bar = 'parent value';
public static function test()
{
var_dump('I am your father');
var_dump('self:: here means '.self::$bar);
var_dump('static:: here means '.static::$bar);
}
}
class Bar extends Foo
{
protected static $bar = 'child value';
public static function test()
{
parent::Test();
var_dump('I am the child');
var_dump('self:: here means '.self::$bar);
var_dump('static:: here means '.static::$bar);
}
}
Bar::test();
Foo::test();
This produces the following output (I have added Line Breaks for clarity):
'I am your father' (length=16)
'self:: here means parent value' (length=30)
'static:: here means child value' (length=31)
'I am the child' (length=14)
'self:: here means child value' (length=29)
'static:: here means child value' (length=31)
'I am your father' (length=16)
'self:: here means parent value' (length=30)
'static:: here means parent value' (length=32)
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