MPV
MPV

Reputation: 1664

PHP const/static variables not usable in static context by parent class

For some reason (which?), PHP const/static variables defined in a child class are not usable in a static context by the parent class.

Why?

Example 1:

class Model{
  function getAll(){
    $query = "SELECT * FROM " . self::DATABASE_TABLE_NAME;
    // ...
  }
}

class Post extends Model{
  const DATABASE_TABLE_NAME = 'post';
}

$p = Post::getAll();

When I run that I get:

Fatal error: Undefined class constant 'DATABASE_TABLE_NAME' on line 3 

(The row with $query = ...)

Example 2:

class Model{
    function getAll(){
        $query = "SELECT * FROM " . self::$DATABASE_TABLE_NAME;
        // ...
    }
}

class Post extends Model{
    static $DATABASE_TABLE_NAME = 'post';
}

$p = Post::getAll();

Then I get:

Fatal error: Access to undeclared static property: Model::$DATABASE_TABLE_NAME on line 3

(Same row)

Upvotes: 3

Views: 3237

Answers (3)

Crozin
Crozin

Reputation: 44406

PHP5.3 introduced late static binding — that's what you're looking for.

class ParentClass {
    public function getAll() {
        var_dump('Get all from ' . static::TABLE_NAME);
    }
}

class ChildClass extends ParentClass {
    const TABLE_NAME = 'my_table_name';
}

$c = new ChildClass();
$c->getAll(); // Get all from my_table_name

EDIT:

However you should design your classes a little bit different. The above solution relies on language dynamics (you can refer to something (eg. a class constant) that doesn't even exists). In such a simple example everything is fine but in real word cases this leads to producing horrible and hard to maintain code.

It'd be better to force the delivered class (ChildClass) to implement some method that returns table name:

abstract class ParentClass {
   // getAll function

   abstract protected function getTableName();
}

class ChildClass extends ParentClass {
    // You have to implement this method
    protected function getTableName() {
        return 'table name';
    }
}

Upvotes: 6

MPV
MPV

Reputation: 1664

I found the answer here: How can I get the classname from a static call in an extended PHP class?

Solution:

class Model{
    function getAll(){
        $class = get_called_class();
        $query = "SELECT * FROM " . $class::$DATABASE_TABLE_NAME;
        // ...
    }
}

class Post extends Model{
    static $DATABASE_TABLE_NAME = 'post';
}

$p = Post::getAll();

Upvotes: 2

RobertPitt
RobertPitt

Reputation: 57278

There all available.

Under the static context you should be using late static binding so that the code would become:

$query = "SELECT * FROM " . static::$DATABASE_TABLE_NAME;

i would also advise you to use constants for sanity reasons.

Upvotes: 0

Related Questions