Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP abstract properties

People also ask

What is the property of abstract methods in PHP?

Abstract classes and methods are when the parent class has a named method, but need its child class(es) to fill out the tasks. An abstract class is a class that contains at least one abstract method. An abstract method is a method that is declared, but not implemented in the code.

Can abstract classes have properties PHP?

An abstract class can have properties and methods as a regular class. But it cannot be instantiated. In most cases, an abstract class will contain at least one abstract method though it is not required.

What are abstract properties?

An abstract property declaration does not provide an implementation of the property accessors -- it declares that the class supports properties, but leaves the accessor implementation to derived classes. The following example demonstrates how to implement the abstract properties inherited from a base class.

What is an abstract class PHP?

Abstract classes are the classes in which at least one method is abstract. Unlike C++ abstract classes in PHP are declared with the help of abstract keyword. Use of abstract classes are that all base classes implementing this class should give implementation of abstract methods declared in parent class.


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';