文字

get_class

(PHP 4, PHP 5, PHP 7)

get_class返回对象的类名

说明

string get_class ([ object $obj ] )

返回对象实例 obj 所属类的名字。如果 obj 不是一个对象则返回 FALSE

Note: 在 PHP 扩展库中定义的类返回其原始定义的名字。在 PHP 4 中 get_class() 返回用户定义的类名的小写形式,但是在 PHP 5 中将返回类名定义时的名字,如同扩展库中的类名一样。

Note:

自 PHP 5 起,如果在对象的方法中调用则 obj 为可选项。

Example #1 使用 get_class()

<?php

class  foo  {
    function 
foo ()
    {
    
// implements some logic
    
}

    function 
name ()
    {
        echo 
"My name is "  get_class ( $this ) ,  "\n" ;
    }
}

// create an object
$bar  = new  foo ();

// external call
echo  "Its name is "  get_class ( $bar ) ,  "\n" ;

// internal call
$bar -> name ();

?>

以上例程会输出:

Its name is foo
My name is foo

参见 get_parent_class() gettype() is_subclass_of()

参数

object

The tested object. This parameter may be omitted when inside a class.

返回值

Returns the name of the class of which object is an instance. Returns FALSE if object is not an object.

If object is omitted when inside a class, the name of that class is returned.

错误/异常

If get_class() is called with anything other than an object, an E_WARNING level error is raised.

更新日志

版本 说明
Since 5.3.0 NULL became the default value for object, so passing NULL to object now has the same result as not passing any value.
Since 5.0.0 The class name is returned in its original notation.
Since 5.0.0 The object parameter is optional if called from the object's method.

范例

Example #2 Using get_class()

<?php

class  foo  {
    function 
name ()
    {
        echo 
"My name is "  get_class ( $this ) ,  "\n" ;
    }
}

// create an object
$bar  = new  foo ();

// external call
echo  "Its name is "  get_class ( $bar ) ,  "\n" ;

// internal call
$bar -> name ();

?>

以上例程会输出:

Its name is foo
My name is foo

Example #3 Using get_class() in superclass

<?php

abstract class  bar  {
    public function 
__construct ()
    {
        
var_dump ( get_class ( $this ));
        
var_dump ( get_class ());
    }
}

class 
foo  extends  bar  {
}

new 
foo ;

?>

以上例程会输出:

string(3) "foo"
string(3) "bar"

参见

  • get_called_class() - 后期静态绑定("Late Static Binding")类的名称
  • get_parent_class() - 返回对象或类的父类名
  • gettype() - 获取变量的类型
  • is_subclass_of() - 如果此对象是该类的子类,则返回 TRUE

用户评论:

[#1] RQuadling at GMail dot com [2014-12-19 15:09:43]

With regard to getting the class name from a namespaced class name, then using basename() seems to do the trick quite nicely.

<?php
namespace Foo\Bar;

abstract class 
Baz
{
  public function 
report()
  {
    echo
      
'__CLASS__        '__CLASS__' 'basename(__CLASS__), PHP_EOL,
      
'get_called_class 'get_called_class(), ' 'basename(get_called_class()), PHP_EOL;
  }
}

class 
Snafu extends Baz
{
}

(new 
Snafu)->report();
?>


produces output of ...

__CLASS__        Foo\Bar\Baz   Baz
get_called_class Foo\Bar\Snafu Snafu

[#2] jjanak at webperfection dot net [2014-10-03 11:06:23]

>= 5.5

::class
fully qualified class name, instead of get_class

<?php
namespace my\library\mvc;

class Dispatcher {}

print Dispatcher::class; // FQN == my\library\mvc\Dispatcher

$disp = new Dispatcher;

print $disp::class; // parse error

[#3] Anonymous [2014-09-18 20:55:26]

If you want the path to an file if you have i file structure like this

project -> system -> libs -> controller.php
project -> system -> modules -> foo -> foo.php

and foo() in foo.php extends controller() in controller.php like this

<?PHP
namespace system\modules\foo;

class 
foo extends \system\libs\controller {
    public function 
__construct() {
        
parent::__construct();    
    }
}
?>


and you want to know the path to foo.php in controller() this may help you

<?PHP
namespace system\libs;

class 
controller {
    protected function 
__construct() {
        
$this->getChildPath();
    }
    protected function 
getChildPath() {
        echo 
dirname(get_class($this));
    }
}
?>


<?PHP
$f 
= new foo();  // system\modules\foo
?>

[#4] var23rav at gmail dot com [2014-08-27 13:52:04]

class A
{
function __construct(){
//parent::__construct();
echo $this->m =  'From constructor A: '.get_class();
echo $this->m =  'From constructor A:- argument = $this: '.get_class($this);

echo $this->m =  'From constructor A-parent: '.get_parent_class();
echo $this->m =  'From constructor A-parent:- argument =  $this: '.get_parent_class($this);
}
}
class B extends A
{
function __construct(){
parent::__construct();
echo $this->m =  'From constructor B: '.get_class();
echo $this->m =  'From constructor B:- argument =  $this: '.get_class($this);

echo $this->m =  'From constructor B-parent: '.get_parent_class();
echo $this->m =  'From constructor B-parent:- argument =  $this: '.get_parent_class($this);
}
}
$b = new B();
//----------------output--------------------

From constructor A: A
From constructor A:- argument = $this: B
From constructor A-parent: 
From constructor A-parent:- argument = $this: A
From constructor B: B
From constructor B:- argument = $this: B
From constructor B-parent: A
From constructor B-parent:- argument = $this: A

Use get_class() to get the name of class  ,it will help you get the class name, in case you extend that class with another class and want to get the name of the class to which object is instance of user get_class($object)

when you create an object of class{$b object of B} which has a super class{Class A}. 
uses these code IN Super Class {A} 
--------------------------------------------
to get class name B{object instance} :  get_class($this)  
to get class name A{super class}  : get_class() or get_parent_class($this)

[#5] alastair at propcom dot co dot uk [2014-05-20 08:12:56]

Not mentioned are namespaces. get_class() returns the class in a suitable format to be used to look up the class again, i.e. 'Namespace\Class_Name'. 

Explode on '\\' to get the components.

[#6] dave at shax dot com [2014-03-06 16:36:57]

A lot of people in other comments wanting to get the classname without the namespace. Some weird suggestions of code to do that - not what I would've written! So wanted to add my own way.

<?php
function get_class_name($classname)
{
    if (
$pos strrpos($classname'\\')) return substr($classname$pos 1);
    return 
$pos;
}
?>


Also did some quick benchmarking, and strrpos() was the fastest too. Micro-optimisations = macro optimisations!

39.0954 ms - preg_match()
28.6305 ms - explode() + end()
20.3314 ms - strrpos()

(For reference, here's the debug code used. c() is a benchmarking function that runs each closure run 10,000 times.)

<?php
c
(
    function(
$class 'a\b\C') {
        if (
preg_match('/\\\\([\w]+)$/'$class$matches)) return $matches[1];
        return 
$class;
    },
    function(
$class 'a\b\C') {
        
$bits explode('\\'$class);
        return 
end($bits);
    },
    function(
$class 'a\b\C') {
        if (
$pos strrpos($class'\\')) return substr($class$pos 1);
        return 
$pos;
    }
);
?>

[#7] Nanhe Kumar [2013-12-20 12:14:02]

<?php
class Parent{
}
class 
Child extends Parent{    
}
$c = new Child();
echo 
get_class($c//Child
?>

<?php
class Parent{
  public function 
getClass(){
     echo 
get_class(); 
  }
}
class 
Child extends Parent{
}
$obj = new Child();
$obj->getClass(); //outputs Parent
?>

<?php
class Parent{
  public function 
getClass(){
     echo 
get_class($this); 
  }
}
class 
Child extends Parent{
}
$obj = new Child();
$obj->getClass(); // Parent
?>

[#8] emmanuel dot antico at gmail dot com [2013-05-10 19:35:51]


function get_real_class($obj) {
    $classname = get_class($obj);

    if (preg_match('@\\\\([\w]+)$@', $classname, $matches)) {
        $classname = $matches[1];
    }

    return $classname;
}

[#9] macnimble at gmail dot com [2012-03-17 19:24:34]

Need a quick way to parse the name of a class when it's namespaced? Try this:

<?php
namespace Engine;
function 
parse_classname ($name)
{
  return array(
    
'namespace' => array_slice(explode('\\'$name), 0, -1),
    
'classname' => join(''array_slice(explode('\\'$name), -1)),
  );
}
final class 
Kernel
{
  final public function 
__construct ()
  {
    echo 
'<pre>'print_r(parse_classname(__CLASS__),1), '</pre>';
    
// Or this for a one-line method to get just the classname:
    // echo join('', array_slice(explode('\\', __CLASS__), -1));
  
}
}
new 
Kernel();
?>


Outputs:
Array
(
    [namespace] => Array
        (
            [0] => Engine
        )

    [classname] => Kernel
)

[#10] mail dot temc at gmail dot com [2011-12-06 14:51:12]

People seem to mix up what __METHOD__, get_class($obj) and get_class() do, related to class inheritance.

Here's a good example that should fix that for ever:

<?php

class Foo {
 function 
doMethod(){
  echo 
__METHOD__ "\n";
 }
 function 
doGetClassThis(){
  echo 
get_class($this).'::doThat' "\n";
 }
 function 
doGetClass(){
  echo 
get_class().'::doThat' "\n";
 }
}

class 
Bar extends Foo {

}

class 
Quux extends Bar {
 function 
doMethod(){
  echo 
__METHOD__ "\n";
 }
 function 
doGetClassThis(){
  echo 
get_class($this).'::doThat' "\n";
 }
 function 
doGetClass(){
  echo 
get_class().'::doThat' "\n";
 }
}

$foo = new Foo();
$bar = new Bar();
$quux = new Quux();

echo 
"\n--doMethod--\n";

$foo->doMethod();
$bar->doMethod();
$quux->doMethod();

echo 
"\n--doGetClassThis--\n";

$foo->doGetClassThis();
$bar->doGetClassThis();
$quux->doGetClassThis();

echo 
"\n--doGetClass--\n";

$foo->doGetClass();
$bar->doGetClass();
$quux->doGetClass();

?>


OUTPUT:

--doMethod--
Foo::doMethod
Foo::doMethod
Quux::doMethod

--doGetClassThis--
Foo::doThat
Bar::doThat
Quux::doThat

--doGetClass--
Foo::doThat
Foo::doThat
Quux::doThat

[#11] ozana at omdesign dot cz [2011-11-28 07:53:24]

Simplest way how to gets Class without namespace

<?php
namespace a\b\c\d\e\f;

class 
Foo {

  public function 
__toString() {
    
$class explode('\\'__CLASS__);
    return 
end($class);
  }
}

echo new 
Foo(); // prints Foo
?>

[#12] Michael Richey [2011-10-31 12:01:22]

Attempting various singleton base class methods described on this page, I have created a base class and bridge function that allows it to work without get_called_class() if it's not available.  Unlike other methods listed here, I chose not to prevent use of __construct() or __clone().

<?php
abstract class Singleton {
    protected static 
$m_pInstance;
    final public static function 
getInstance(){
        
$class = static::getClass();
        if(!isset(static::
$m_pInstance[$class])) {
            static::
$m_pInstance[$class] = new $class;
        }
        return static::
$m_pInstance[$class];
    }
    final public static function 
getClass(){
        return 
get_called_class();
    }
}

// I don't remember where I found this, but this is to allow php < 5.3 to use this method.
if (!function_exists('get_called_class')) {
    function 
get_called_class($bt false$l 1) {
        if (!
$bt)
            
$bt debug_backtrace();
        if (!isset(
$bt[$l]))
            throw new 
Exception("Cannot find called class -> stack level too deep.");
        if (!isset(
$bt[$l]['type'])) {
            throw new 
Exception('type not set');
        }
        else
            switch (
$bt[$l]['type']) {
                case 
'::':
                    
$lines file($bt[$l]['file']);
                    
$i 0;
                    
$callerLine '';
                    do {
                        
$i++;
                        
$callerLine $lines[$bt[$l]['line'] - $i] . $callerLine;
                    } while (
stripos($callerLine$bt[$l]['function']) === false);
                    
preg_match('/([a-zA-Z0-9\_]+)::' $bt[$l]['function'] . '/'$callerLine$matches);
                    if (!isset(
$matches[1])) {
                        
// must be an edge case.
                        
throw new Exception("Could not find caller class: originating method call is obscured.");
                    }
                    switch (
$matches[1]) {
                        case 
'self':
                        case 
'parent':
                            return 
get_called_class($bt$l 1);
                        default:
                            return 
$matches[1];
                    }
                
// won't get here.
                
case '->': switch ($bt[$l]['function']) {
                        case 
'__get':
                            
// edge case -> get class of calling object
                            
if (!is_object($bt[$l]['object']))
                                throw new 
Exception("Edge case fail. __get called on non object.");
                            return 
get_class($bt[$l]['object']);
                        default: return 
$bt[$l]['class'];
                    }

                default: throw new 
Exception("Unknown backtrace method type");
            }
    }
}

class 
extends Singleton {
}

class 
extends Singleton {
}

$b B::getInstance();
echo 
'class: '.get_class($b);

echo 
'<br />';

$c C::getInstance();
echo echo 
'class: '.get_class($c);
?>

This returns:
class: b
class: c

[#13] me at nwhiting dot com [2010-12-06 08:14:04]

Method for pulling the name of a class with namespaces pre-stripped.

<?php

function get_class_name($object null)
{
    if (!
is_object($object) && !is_string($object)) {
        return 
false;
    }
    
    
$class explode('\\', (is_string($object) ? $object get_class($object)));
    return 
$class[count($class) - 1];
}
?>


And for everyone for Unit Test goodiness!

<?php
namespace testme\here;

class 
TestClass {
    
    public function 
test()
    {
       return 
get_class_name(get_class());
    }
}

class 
GetClassNameTest extends \PHPUnit_Framework_TestCase
{
    public function 
testGetClassName()
    {
        
$class  = new TestClass();
        
$std  = new \stdClass();
        
$this->assertEquals('TestClass'get_class_name($class));
        
$this->assertEquals('stdClass'get_class_name($std));
        
$this->assertEquals('Test'get_class_name('Test'));
        
$this->assertFalse(get_class_name(null));
        
$this->assertFalse(get_class_name(array()));
        
$this->assertEquals('TestClass'$class->test());
    }
}
?>

[#14] Aaron [2010-06-18 11:14:58]

This can sometimes be used in place of get_called_class(). I used this function in a parent class to get the name of the class that extends it.

[#15] ovidiu.bute [at] gmail.com [2010-04-05 22:23:00]

If you are using namespaces this function will return the name of the class including the namespace, so watch out if your code does any checks for this. Ex:

namespace Shop;

<?php
class Foo
{
  public function 
__construct()
  {
     echo 
"Foo";
  }
}

//Different file

include('inc/Shop.class.php'); 

$test = new Shop\Foo();
echo 
get_class($test);//returns Shop\Foo
?>

[#16] Tom Brown [2009-09-17 11:02:44]

As of 5.3.0 this function seems to have started throwing an E_WARNING error if you pass it a non-object. Supress that with "@" if you are actually checking and handling the false return code.

[#17] Lanselot [2009-02-11 02:09:57]

Beware if you're omitting the parameter on inherited classes.
It'll return the class name of the method where it's called.

<?php
class {
    function 
foo() {
      return 
get_class();
    }
}
class 
extends {
   function 
bar() {
      return 
get_class();
   }
}
$instance = new B();
echo 
$instance->bar(); //Prints 'B';
echo $instance->foo(); //Prints 'A';
?>

[#18] danbettles at yahoo dot co dot uk [2008-10-08 11:56:02]

It is possible to write a completely self-contained Singleton base class in PHP 5.3 using the new get_called_class function.  When called in a static method, this function returns the name of the class the call was made against.

<?php

abstract class Singleton {

    protected function 
__construct() {
    }

    final public static function 
getInstance() {
        static 
$aoInstance = array();

        
$calledClassName get_called_class();

        if (! isset (
$aoInstance[$calledClassName])) {
            
$aoInstance[$calledClassName] = new $calledClassName();
        }

        return 
$aoInstance[$calledClassName];
    }

    final private function 
__clone() {
    }
}

class 
DatabaseConnection extends Singleton {

    protected 
$connection;

    protected function 
__construct() {
        
// @todo Connect to the database
    
}

    public function 
__destruct() {
        
// @todo Drop the connection to the database
    
}
}

$oDbConn = new DatabaseConnection();  // Fatal error

$oDbConn DatabaseConnection::getInstance();  // Returns single instance
?>


Full write-up in Oct 2008: http://danbettles.blogspot.com

[#19] Maik [2008-10-04 08:36:38]

The code just worked fine with PHP 5.3.
Thanks to you it could be rebuild to work with earlier versions of PHP 5.

I just changed the 'static' to 'self' and die() to an Exception.

<?php
// This one extends Singleton with proper class name
class someSingleton extends Singleton {
    public static function 
getInstance() {
        
parent::$__CLASS__ __CLASS__;
        
parent::getInstance();
    }
}
// This one does the logic
abstract class Singleton {
    protected static 
$__CLASS__ __CLASS__;
    protected static 
$instance null;

    protected function 
__construct() {}   
    abstract protected function 
init();
   
    

    
public static function getInstance() {       
        
$class self::getClass();
       
        if (
self::$instance === null) {
            
self::$instance = new $class();
            
self::$instance->init();
        }
       
        return 
self::$instance;
    }
   
    

    
private static function getClass() {
        
$implementing_class self::$__CLASS__;
        
$original_class __CLASS__;

        if (
$implementing_class === $original_class)
            throw new 
Exception("You MUST provide a <code>protected static \$__CLASS__ = __CLASS__;</code> statement in your Singleton-class!");
       
        return 
$implementing_class;
    }
}
?>

[#20] Edward [2008-08-21 03:26:42]

The code in my previous comment was not completely correct. I think this one is. 

<?php
abstract class Singleton {
    protected static 
$__CLASS__ __CLASS__;

    protected function 
__construct() {
    }
    
    abstract protected function 
init();
    
    

    
public static function getInstance() {
        static 
$instance;
        
        
$class self::getClass();
        
        if (
$instance === null) {
            
$instance = new $class();
            
$instance->init();
        }
        
        return 
$instance;
    }
    
    

    
private static function getClass() {
        
$implementing_class = static::$__CLASS__;
        
$original_class __CLASS__;

        if (
$implementing_class === $original_class) {
            die(
"You MUST provide a <code>protected static \$__CLASS__ = __CLASS__;</code> statement in your Singleton-class!");
        }
        
        return 
$implementing_class;
    }
}
?>

[#21] Edward [2008-08-20 05:42:01]

With Late Static Bindings, available as of PHP 5.3.0, it is now possible to implement an abstract Singleton class with minimal overhead in the child classes. Late static bindings are explained here: http://nl2.php.net/manual/en/language.oop5.late-static-bindings.php

In short, it introduces a new 'static::' keyword, that is evaluated at runtime. In the following code I use it to determine the classname of the child Singleton class.

<?php
abstract class Singleton {
    protected static 
$__CLASS__ __CLASS__;
    protected static 
$instance;
    
    protected function 
__construct() {
        static::
$instance $this;
        
$this->init();
    }
    
    abstract protected function 
init();
    
    protected function 
getInstance() {
        
$class = static::getClass();
        
        if (static::
$instance===null) {
            static::
$instance = new $class;
        }

        return static::
$instance;
    }
    
    private static function 
getClass() {
        if (static::
$__CLASS__ == __CLASS__) {
            die(
"You MUST provide a <code>protected static \$__CLASS__ = __CLASS__;</code> statement in your Singleton-class!");
        }
        
        return static::
$__CLASS__;
    }
}
?>


An example Singleton class can then be implemented as follows:

<?php
class extends Singleton {
    protected static 
$__CLASS__ __CLASS__// Provide this in each singleton class.

    
protected function someFunction() {
        
$instance = static::getInstance();
        
// ...
    
}
}
?>


Hope this helps you save some time :)

[#22] James [2008-06-22 02:46:08]

To get round this problem, another option is a factory to create singletons.

<?php
class Factory {
  private static 
$instances = array();
  public static function 
getInstance($class_name) {
    if(!
array_key_exists($class_nameself::$instances)) {
      
self::$instances[$class_name] = new $class_name();
    }
    return 
self::$instances[$class_name];
  }
}
?>


I guess you could modify this to create singletons from some, and prototypes for the rest.

There's probably some good way to stop people instantiating objects directly. Perhaps by using the backtrace in the constructor of the class to ensure that it was indeed the Factory that created the object.

[#23] Anonymous [2008-04-29 21:59:04]

I jumped the gun. The following code also working for statics called inside other classes.

<?php
        
for( $i=$i count($bt) ; $i++)
        {
            if(
$bt[$i]['function'] == 'getInstance')
            {
                
$class $bt[$i]['class'];
                
            } else {
                break;
            }
        }
?>

[#24] dave dot zap at gmail dot com [2008-04-29 21:13:43]

Take care using the backtrace method to find the calling class of a static method, you should step backward through the array and find a match for your getInstance() function. In backtrace the class name you want is not always the last item in the array.

I will not post the whole singleton class here, but have made the following modification to Frederik Krautwald's method (found below)

<?php 
$bt 
debug_backtrace();
// this method is count($bt)-1) by Frederik will fall over when calling getInstance from within an include file.
//$class = $bt[count($bt) - 1]['class'];

for( $i=count($bt)-$i $i--)
{
    if(
$bt[$i]['function'] == 'getInstance')
    {
        
$class $bt[$i]['class'];
        break;
    }
}
?>

[#25] Anonymous [2008-04-12 14:01:44]

In Perl (and some other languages) you can call some methods in both object and class (aka static) context. I made such a method for one of my classes in PHP5, but found out that static methods in PHP5 do not 'know' the name of the calling subclass', so I use a backtrace to determine it. I don't like hacks like this, but as long as PHP doesn't have an alternative, this is what has to be done:

public function table_name() {
$result = null;
if (isset($this)) { // object context
$result = get_class($this);
}
else { // class context
$result = get_class();
$trace = debug_backtrace();
foreach ($trace as &$frame) {
if (!isset($frame['class'])) {
break;
}
if ($frame['class'] != $result) {
if (!is_subclass_of($frame['class'], $result)) {
break;
}
$result = $frame['class'];
}
}
}
return $result;
}

[#26] frederic dot sureau at gmail dot com [2008-02-29 11:01:24]

@ hek :

The problem is that the method getInstance() in a Singleton must be static, so we cannot use $this because it doesn't exists :(

[#27] andregs at NOSPAM dot gmail dot NOSPAM dot com [2008-02-21 13:17:27]

After reading the previous comments, this is the best I've done to get the final class name of a subclass:

<?php

class Singleton
{
   private static 
$_instances = array();
   protected final function 
__construct(){}
   
   

   
protected static function getInstance()
   {
      
$classname func_get_arg(0);
      if (! isset(
self::$_instances[$classname]))
      {
         
self::$_instances[$classname] = new $classname();
      }
      return 
self::$_instances[$classname];
   }
   
}

class 
Child extends Singleton
{
   

   
public static function getInstance()
   {
      return 
parent::getInstance(get_class());
   }
}

?>


Subclasses must override "getInstance" and cannot override "__construct".

[#28] dodgie74 at NOSPAM dot yahoo dot NOSPAM dot co dot uk [2007-09-09 05:40:46]

As noted in bug #30934 (which is not actually a bug but a consequence of a design decision), the "self" keyword is bound at compile time. Amongst other things, this means that in base class methods, any use of the "self" keyword will refer to that base class regardless of the actual (derived) class on which the method was invoked. This becomes problematic when attempting to call an overridden static method from within an inherited method in a derived class. For example:

<?php
class Base
{
    protected 
$m_instanceName '';
    
    public static function 
classDisplayName()
    {
        return 
'Base Class';
    }
    
    public function 
instanceDisplayName()
    {
        
//here, we want "self" to refer to the actual class, which might be a derived class that inherits this method, not necessarily this base class
        
return $this->m_instanceName ' - ' self::classDisplayName();
    }
}

class 
Derived extends Base
{
    public function 
Derived$name )
    {
        
$this->m_instanceName $name;
    }
    
    public static function 
classDisplayName()
    {
        return 
'Derived Class';
    }
}

$o = new Derived('My Instance');
echo 
$o->instanceDisplayName();
?>


In the above example, assuming runtime binding (where the keyword "self" refers to the actual class on which the method was invoked rather than the class in which the method is defined) would produce the output:

My Instance - Derived Class

However, assuming compile-time binding (where the keyword "self" refers to the class in which the method is defined), which is how php works, the output would be:

My Instance - Base Class

The oddity here is that "$this" is bound at runtime to the actual class of the object (obviously) but "self" is bound at compile-time, which seems counter-intuitive to me. "self" is ALWAYS a synonym for the name of the class in which it is written, which the programmer knows so s/he can just use the class name; what the programmer cannot know is the name of the actual class on which the method was invoked (because the method could be invoked on a derived class), which it seems to me is something for which "self" ought to be useful.

However, questions about design decisions aside, the problem still exists of how to achieve behaviour similar to "self" being bound at runtime, so that both static and non-static methods invoked on or from within a derived class act on that derived class. The get_class() function can be used to emulate the functionality of runtime binding for the "self" keyword for static methods:

<?php
class Base
{
    protected 
$m_instanceName '';
    
    public static function 
classDisplayName()
    {
        return 
'Base Class';
    }
    
    public function 
instanceDisplayName()
    {
        
$realClass get_class($this);
        return 
$this->m_instanceName ' - ' call_user_func(array($realClass'classDisplayName'));
    }
}

class 
Derived extends Base
{
    public function 
Derived$name )
    {
        
$this->m_instanceName $name;
    }
    
    public static function 
classDisplayName()
    {
        return 
'Derived Class';
    }
}

$o = new Derived('My Instance');
echo 
$o->instanceDisplayName();
?>


Output:
My Instance - Derived Class

I realise that some people might respond "why don't use just just the class name with ' Class' appended instead of the classDisplayName() method", which is to miss the point. The point is not the actual strings returned but the concept of wanting to use the real class for an overridden static method from within an inherited non-static method. The above is just a simplified version of a real-world problem that was too complex to use as an example.

Apologies if this has been mentioned before.

[#29] bramus at bram dot us [2007-08-20 08:40:06]

@ Frederik : 

<?php
$class 
$bt[count($bt) - 1]['class']; 
?>


should be

<?php
$class 
$bt[count($bt) - 2]['class'];
?>


;-)

[#30] Frederik Krautwald [2007-06-25 08:13:04]

Due to PHP 5 engine that permits to get final class in a static called function, and this is a modified version of examples published below.

<?php
abstract class Singleton {
    protected static 
$_instances = array();
   
    protected function 
__construct() {}
   
    protected static function 
getInstance() {
        
$bt debug_backtrace();
        
$class $bt[count($bt) - 1]['class'];
        if (!isset(
self::$_instances[$class])) {
            
self::$_instances[$class] = new $class();
        }
        return 
self::$_instances[$class];
    }
}
class 
extends Singleton {
    public static function 
getInstance() {
        return 
parent::getInstance();
    }
}
class 
extends Singleton {
    public static function 
getInstance() {
        return 
parent::getInstance();
    }
}
class 
extends {
    public static function 
getInstance() {
        return 
parent::getInstance();
    }
}

$a A::getInstance();
$b B::getInstance();
$c C::getInstance();

echo 
"\$a is a " get_class($a) . "<br />";
echo 
"\$b is a " get_class($b) . "<br />";
echo 
"\$c is a " get_class($c) . "<br />";
?>


I don't know about if performance would increase if debug_backtrace() is skipped and instead have getInstance() to accept a passed class retrieved by get_class() method as parameter as described in a post below.

By having set getInstance() to protected in the Singleton class, the function is required to be overridden (good OOP practice).

One thing to mention is, that there is no error checking in case $class is null or undefined, which would result in a fatal error. At the moment, though, I can't see how it could happen when the getInstance() is protected, i.e. has to be overridden in a subclass -- but with good coding practice you should always error check.

[#31] mightye at gmail dot com [2007-06-23 06:20:22]

To: Bryan

In this model it is still workable if your singleton variable is actually an array.  Consider:
<?php
abstract class Singleton {
    protected final static 
$instances = array();
    
    protected 
__construct(){}
    
    protected function 
getInstance() {
        
$class get_real_class(); // imaginary function returning the final class name, not the class the code executes from
        
if (!isset(self::$instances[$class])) {
            
self::$instances[$class] = new $class();
        }
        return 
self::$instances[$class];
    }
}
class 
extends Singleton {
}
class 
extends Singleton {
}

$a A::getInstance();
$b B::getInstance();

echo 
"\$a is a " get_class($a) . "<br />";
echo 
"\$b is a " get_class($b) . "<br />";
?>

This would output:
$a is a A
$b is a B

The only alternative as described elsewhere is to make getInstance() protected abstract, accept the class name as an argument, and extend this call with a public final method for every sub-class which uses get_class() in its local object scope and passes it to the superclass.

Or else create a singleton factory like this:
<?php
final class SingletonFactory {
    protected static 
$instances = array();
    
    protected 
getInstance($class) {
        if (!isset(
self::$instances[$class])) {
            
self::$instances[$class] = new $class();
        }
        return 
self::$instances[$class];
    }
}
?>

The downside to this of course to this latter model is that the class itself doesn't get to decide if it is a singleton, the calling code gets to decide this instead, and a class that really wants or *needs* to be a singleton has no way to enforce this, not even by making its constructor protected.

Basically these design patterns, and various other meta manipulations (things which operate on the nature of the object, not on the data the object holds) could benefit greatly from knowing exactly what the final type of this object is, and not having native access to this information obligates work-arounds.

[#32] Bryan [2007-06-19 08:07:21]

janci's Singleton example is all well and good, until you create another class "Bar" which also extends Singleton.

<?php
$single_foo 
Foo::getInstance();
$single_bar Bar::getInstance();
?>


$single_bar will now be an instance of Foo! This is because there is only one copy of the static variable $__instance in the Singleton class. Here is a better Singleton class:

<?php
abstract class Singleton {
    static 
$_instances = array();

    
//Prevent singletons from being instantiated other than via getInstance();
    
protected function __construct() {}
    protected function 
__clone() {}
       
    static function 
getInstance($class_name) {
        if(!isset(
self::$_instances[$class_name])) {
            
self::$_instances[$class_name] = new $class_name();
        }
        return 
self::$_instances[$class_name];
    }
}
?>


Unfortunately, you are still required to define Foo as janci does. I would love to see an example where the only thing you add to the class is "extends Singleton" and you're done, but that seems to be impossible.

[#33] janci [2007-04-30 12:00:30]

To yicheng zero-four at gmail dot com: Another, maybe better example where finding out the real class (not the class we are in) in static method should be quite usefull is the Singleton pattern. 

There is currently no way how to create an abstract Singleton class that could be used just by extending it without the need to change the extended class. Consider this example:
<?php
abstract class Singleton
{
    protected static 
$__instance false;
        
    public static function 
getInstance()
    {    
        if (
self::$__instance == false)
        {
            
// This acctually is not what we want, $class will always be 'Singleton' :(
            
$class get_class();
            
self::$__instance = new $class();            
        }
        return 
self::$__instance;
    }
}

class 
Foo extends Singleton
{
    
// ...
}

$single_foo Foo::getInstance();
?>

This piece of code will result in a fatal error saying: Cannot instantiate abstract class Singleton in ... on line 11

The best way I figured out how to avoid this requires simple but still a change of the extended (Foo) class:
<?php
abstract class Singleton
{
    protected static 
$__instance false;
        
    protected static function 
getInstance($class)
    {    
        if (
self::$__instance == false)
        {
            if (
class_exists($class))
            {
                
self::$__instance = new $class();            
            }
            else 
            {
                throw new 
Exception('Cannot instantiate undefined class [' $class ']'1);
            }
        }
        return 
self::$__instance;
    }
}

class 
Foo extends Singleton
{
    
// You have to overload the getInstance method in each extended class:
    
public static function getInstance()
    {
        return 
parent::getInstance(get_class());
    }
}

$single_foo Foo::getInstance();
?>


This is of course nothing horrible, you will propably need to change something in the extended class anyway (at least the constructor access), but still... it is just not as nice as it possibly could be ;)

[#34] yicheng zero-four at gmail dot com [2007-04-27 12:29:48]

To matsgefvert dot se and Marc,

I'm sorry but I'm still having a very difficult time understanding why you would want this behavior.  I understand that you are generating some code for some persistent layer for database access.  

In your code example, Marc, you say that you would like the SomeTable::read() to return "SomeTable" when called from your client.  Yet, at this point you *know* what the class name is.  Even assuming you are generating this code automatically, you can simply generate your SomeTable class as such.

<?php

class PersistedObject {
  
//...
  
public static function read($table$key){
    
// do some databasey stuff 
    // with $table which is the table name
    
return $table;
  }
}

class 
SomeTable extends PersistedObject {
  
//...
  // make a copy in the child class
  
public static function read($key){
    
$table get_class();
    return 
parent::read($table$key);
  }
}

// this will now return "SomeTable"
$someTableObject SomeTable::read(1234);

?>


I'm still failing to see how this would provide but a convenience for very rare & specific issues, at the cost of non-OOP behavior by allowing static methods to bind to objects instead of classes.  

One of the most common uses for get_class() is for debugging lines, for example:

<?php

class PersistedObject {
  
//...
  
public static function transaction($params){
    
// do some stuff
    
if ($error_occurred){
      echo 
"Error : WTFBBQ happened in " get_class() . "::" __FUNCTION__ ".  Time to get some coffee!";
  }
}

class 
SomeTable extends PersistedObject {
  
//...
}

SomeTable::transaction$someParams );
?>


Now, when an error occurs inside the call to SomeTable::transaction(), we get incorrect error output.

[#35] Kerry Kobashi [2007-04-14 23:58:07]

It should be noted that class names are represented in lowercase under PHP 4.x. 

class MyClass {
   function MyClass() {
   }
   function ShowClass() {
      echo get_class($this);
   }
}

$p = new MyClass();
$p->ShowClass();

Displays:

myclass

If you serialize $p, you will also see that the class name is lower case as well:

$p = new MyClass();
echo serialize($p);

Displays:

O:7:"myclass":1:{s:3:"val";i:100;}

In my case, this is an important point for mapping class names to database table names (and vice versa).

[#36] Marc W. [2007-04-13 09:40:26]

The previous comment (from matsgefvert dot se) is 100% correct. To further elaborate on the persistence layers example suggested, consider the case where you are dynamically creating inherited objects. For example:
<?php

class PersistedObject {
//...
public static function read($key){
//You will need the table name here to actually read
// from the persistence medium
echo get_class();
}

class 
SomeTable extends PersistedObject {
//...
}



$someTableObject SomeTable::read(1234);

?>

Remember that the SomeTable class would be generated on the fly, probably by some DB schema. The problem is that you would actually like the above example to output "SomeTable", but unfortunately, it will output "PersistedObject".

[#37] spam at matsgefvert dot se [2007-02-24 01:37:01]

I disagree with the notion that the authors of the previous posts are unfamiliar with OOP. Without the ability to know from general (parent) objects what kind of classes we're operating on, it makes things rather difficult, especially in building frameworks that rely heavily on class types (e.g. persistence layers).

The proposed BooBoof::getclass() and CooCoof::getclass() scheme will not work in some particular scenarios since static calls aren't virtual, which means a parent class will always call its own getclass() function instead of the one needed to find out the class name.

The only solution I've found is to pass along a string containing the class name we're working on to the generalized functions. It is however an ugly solution, certainly less than ideal and goes against what OOP and reflection is all about, IMHO.

[#38] yicheng zero-four at gmail dot com [2007-01-18 12:22:22]

This a response to luke at liveoakinteractive dot com and davidc at php dot net.  Static methods and variables, by definition, are bound to class types not object instances.  You should not need to dynamically find out what class a static method belongs to, since the context of your code should make it quite obvious.  Your questions reveals that you probably don't quite understand OOP quite yet (it took me a while as well).

Luke, the observed behavior from your particular code snippet makes perfect sense when you think about it.  The method getclass() is defined in BooBoof, so the __CLASS__ macro would be bound to BooBoof and defined in relation to the BooBoof class.  The fact that CooCoof is a subclass of BooBoof just means that it gains a shortcut to BooBoof::getclass().  So, in effect, you are really asking (in a convoluted way): "What is the class to which belongs the method call BooBoof::getclass()?"  The correct solution (if you actually want/need to do this) is to simply implement CooCoof::getclass() { return __CLASS__; } inside of the CooCoof definition, and any childclasses that you want to mimic this behavior.  CooCoof::getclass() will have the expected behavior.

[#39] makc dot the dot great at gmail dot com [2006-12-17 09:29:08]

Check it out:

<?php

class {
 function 
() { return "A::s"; }
 function 
s1 () { return $this->s(); }
}

class 
extends {
 function 
() { return "B::s"; }
}

$a = new A(); echo $a->s1();
echo 
"<br>";
$b = new B(); echo $b->s1();
echo 
"<br>";

class 
{
 static function 
() { return "C::s"; }
 static function 
s1 () { return self::s(); }
}

class 
extends {
 static function 
() { return "D::s"; }
}

echo 
C::s1();
echo 
"<br>";
echo 
D::s1();
echo 
"<br>";

?>


Output:
A::s
B::s
C::s
C::s

Seems like static function always belong to its class.

[#40] luke at liveoakinteractive dot com [2006-12-06 07:03:28]

This note is a response to the earlier post by davidc at php dot net. Unfortunately, the solution posted for getting the class name from a static method does not work with inherited classes.

Observe the following:
<?php
class BooBoof {
  public static function 
getclass() {
    return 
__CLASS__;
  }

  public function 
retrieve_class() {
    return 
get_class($this);
  }
}

class 
CooCoof extends BooBoof {
}

echo 
CooCoof::getclass();
// outputs BooBoof

$coocoof = new CooCoof;
echo 
$coocoof->retrieve_class();
// outputs CooCoof
?>


__CLASS__ and get_class($this) do not work the same way with inherited classes. I have been thus far unable to determine a reliable way to get the actual class from a static method.

[#41] benjaminhill at gmail dot com [2006-04-27 10:47:19]

More funkyness:

class Parent {
   function displayTableName() {
      echo get_class($this);
      echo get_class();
   }
}

class Child {
   function __construct() {
      $this->displayTableName();
   }
}

Will return 
- Child
- Parent

So when they say "the object isn't required in PHP5" - they don't really mean it.

[#42] brjann at NOSPAMATALLgmail dot com [2005-11-16 12:39:53]

This behavior is unexpected, but good to be aware of

class parentclass {
public function getClass(){
echo get_class($this); //using "$this"
}
}
class child extends parentclass {
}

$obj = new child();
$obj->getClass(); //outputs "child"

class parentclass {
public function getClass(){
echo get_class(); //note, no "$this"
}
}
class child extends parentclass {
}

$obj = new child();
$obj->getClass(); //outputs "parentclass"

[#43] wired at evd dot ru [2005-09-25 02:25:13]

There is one unexpected bahaviour (for me as least):

<?php

  
class parent
  
{
    ...

    public function 
getInstance ($id)
    {
      ...

      print 
get_class() . "\n" __CLASS__;

      ...
    }
  }

  class 
child extends parent
  
{
    ...
  }

  
child::getInstance(...);
?>


This code will produce:

  parent
  parent

So I can't make "new $className(...)" in getInstance(). The only option is to do a fabric.

[#44] kunxin at creaion dot com [2005-07-25 05:30:56]

I just migrated from PHP 4 to PHP 5 and noticed that in PHP 5.03 that a lot of code dependent on get_class() and its variants stop working.

It turns out that get_class() and its variants are now case-sensitive.

[#45] refrozen dot com [2005-07-05 15:01:22]

philip at cornado dot com, it returns the value of the class from which it was called, rather than the instance's name... causing inheritance to result in unexpected returns

[#46] MagicalTux at FF.ST [2004-02-02 04:11:29]

Note that the constant __CLASS__ is different from get_class($this) :
<?php
  
class test {
    function 
whoami() {
      echo 
"Hello, I'm whoami 1 !\r\n";
      echo 
"Value of __CLASS__ : ".__CLASS__."\r\n";
      echo 
"Value of get_class() : ".get_class($this)."\r\n\r\n";
    }
  }
  class 
test2 extends test {
    function 
whoami2() {
      echo 
"Hello, I'm whoami 2 !\r\n";
      echo 
"Value of __CLASS__ : ".__CLASS__."\r\n";
      echo 
"Value of get_class() : ".get_class($this)."\r\n\r\n";
      
parent::whoami(); // call parent whoami() function
    
}
  }
  
$test=new test;
  
$test->whoami();
  
$test2=new test2;
  
$test2->whoami();
  
$test2->whoami2();
?>


The output is :
Hello, I'm whoami 1 !
Value of __CLASS__ : test
Value of get_class() : test

Hello, I'm whoami 1 !
Value of __CLASS__ : test
Value of get_class() : test2

Hello, I'm whoami 2 !
Value of __CLASS__ : test2
Value of get_class() : test2

Hello, I'm whoami 1 !
Value of __CLASS__ : test
Value of get_class() : test2

In fact, __CLASS__ returns the name of the class the function is in and get_class($this) returns the name of the class which was created.

[#47] Dan [2003-01-29 22:00:16]

This function does return the class name in lowercase, but that does not seem to make any difference. The code below, although very sloppy, works fine in all of the following configurations.

PHP 4.2.2 on Windows NT5 with Apache 1.3.24
PHP 4.2.1 in Zend Development Environment on box above
PHP 4.2.3 on Linux RedHat 7.3 with Apache 1.3.27

class TeSt {
   var $a;
   var $b = "Fred";

   // Notice the case difference in the constructor name

   function Test() {
      $classname = get_class($this); // $classname = "test"
      $this->ra = get_class_vars($classname);
   }
}
// Next line also works with Test(), TEST(), or test()
$obj = new TeSt();
print_r($obj->ra);

Result :
   Array
   (
       [a] => 
       [b] => Fred
   )

[#48] oliver DOT pliquett @mediagear DOT de [2002-08-13 08:07:53]

This function can become _VERY_ helpful if you want to return a new object of the same type. See this example:

<?php
class Foo{
    var 
$name;
    
    function 
Foo$parameter ){
        
$this->name $parameter;
    }

    function 
whoami() {
        echo 
"I'm a " get_class$this ) ."\n";
    }
    
    function 
getNew() {
        
$className get_class$this );
        
        
// here it happens:
        
return new $className "world" ) ;
    }
}
class 
Bar extends Foo {

    function 
Bar$name ){
        
$this->Foo$name );
    }

    function 
welcome() {
        echo 
"Hello, " $this->name .  "! \n";
    } 
}

// We generate a Bar object:
$myBar = new Bar"Oliver" );
$myBar->welcome();

//now let's instanciate a new Bar object. 
//note: this method is inherited from Foo by Bar!

$baba $myBar->getNew();

$baba->welcome();
$baba->whoami();


?>

[#49] philip at cornado dot com [2002-06-20 12:15:11]

As of PHP 4.3.0 the constant __CLASS__ exists and contains the class name.

上一篇: 下一篇: