Getting the name of a child class in the parent class (static context)
I'm building an ORM library with reuse and simplicity in mind; everything goes fine except that I got stuck by a stupid inheritance limitation. Please consider the code below:
class BaseModel {
/*
* Return an instance of a Model from the database.
*/
static public function get (/* varargs */) {
// 1. Notice we want an instance of User
$class = get_class(parent); // value: bool(false)
$class = get_class(self); // value: bool(false)
$class = get_class(); // value: string(9) "BaseModel"
$class = __CLASS__; // value: string(9) "BaseModel"
// 2. Query the database with id
$row = get_row_from_db_as_array(func_get_args());
// 3. Return the filled instance
$obj = new $class();
$obj->data = $row;
return $obj;
}
}
class User extends BaseModel {
protected $table = 'users';
protected $fields = array('id', 'name');
protected $primary_keys = array('id');
}
class Section extends BaseModel {
// [...]
}
$my_user = User::get(3);
$my_user->name = 'Jean';
$other_user = User::get(24);
$other_user->name = 'Paul';
$my_user->save();
$other_user->save();
$my_section = Section::get('apropos');
$my_section->delete();
Obviously, this is not the behavior I was expecting (although the actual behavior also makes sense).. So my question is if you guys know of a mean to get, in the parent class, the name of child class.
Solution 1:
You don't need to wait for PHP 5.3 if you're able to conceive of a way to do this outside of a static context. In php 5.2.9, in a non-static method of the parent class, you can do:
get_class($this);
and it will return the name of the child class as a string.
i.e.
class Parent() {
function __construct() {
echo 'Parent class: ' . get_class() . "\n" . 'Child class: ' . get_class($this);
}
}
class Child() {
function __construct() {
parent::construct();
}
}
$x = new Child();
this will output:
Parent class: Parent
Child class: Child
sweet huh?
Solution 2:
in short. this is not possible. in php4 you could implement a terrible hack (examine the debug_backtrace()
) but that method does not work in PHP5. references:
-
30423
-
37684
-
34421
edit: an example of late static binding in PHP 5.3 (mentioned in comments). note there are potential problems in it's current implementation (src).
class Base {
public static function whoAmI() {
return get_called_class();
}
}
class User extends Base {}
print Base::whoAmI(); // prints "Base"
print User::whoAmI(); // prints "User"
Solution 3:
I know this question is really old, but for those looking for a more practical solution than defining a property in every class containing the class name:
You can use the static
keyword for this.
As explained in this contributor note in the php documentation
the
static
keyword can be used inside a super class to access the sub class from which a method is called.
Example:
class Base
{
public static function init() // Initializes a new instance of the static class
{
return new static();
}
public static function getClass() // Get static class
{
return static::class;
}
public function getStaticClass() // Non-static function to get static class
{
return static::class;
}
}
class Child extends Base
{
}
$child = Child::init(); // Initializes a new instance of the Child class
// Output:
var_dump($child); // object(Child)#1 (0) {}
echo $child->getStaticClass(); // Child
echo Child::getClass(); // Child
Solution 4:
I know its old post but want to share the solution I have found.
Tested with PHP 7+
Use the function get_class()
link
<?php
abstract class bar {
public function __construct()
{
var_dump(get_class($this));
var_dump(get_class());
}
}
class foo extends bar {
}
new foo;
?>
The above example will output:
string(3) "foo"
string(3) "bar"
Solution 5:
In case you don't want to use get_called_class() you can use other tricks of late static binding (PHP 5.3+). But the downside in this case you need to have getClass() method in every model. Which is not a big deal IMO.
<?php
class Base
{
public static function find($id)
{
$table = static::$_table;
$class = static::getClass();
// $data = find_row_data_somehow($table, $id);
$data = array('table' => $table, 'id' => $id);
return new $class($data);
}
public function __construct($data)
{
echo get_class($this) . ': ' . print_r($data, true) . PHP_EOL;
}
}
class User extends Base
{
protected static $_table = 'users';
public static function getClass()
{
return __CLASS__;
}
}
class Image extends Base
{
protected static $_table = 'images';
public static function getClass()
{
return __CLASS__;
}
}
$user = User::find(1); // User: Array ([table] => users [id] => 1)
$image = Image::find(5); // Image: Array ([table] => images [id] => 5)