Comment puis-je obtenir le nom de la classe à partir d'un appel statique dans une classe PHP étendue?

91

J'ai deux classes: Actionet MyAction. Ce dernier est déclaré comme:

class MyAction extends Action {/* some methods here */}

Tout ce dont j'ai besoin est une méthode dans la Actionclasse (uniquement dans celle-ci, car il y aura beaucoup de classes héritées, et je ne veux pas implémenter cette méthode dans toutes), qui retournera le nom de la classe à partir d'un appel statique. Voici de quoi je parle:

Class Action {
 function n(){/* something */}
}

Et quand je l'appelle:

MyAction::n(); // it should return "MyAction"

Mais chaque déclaration de la classe parent n'a accès qu'à la __CLASS__variable de classe parent , qui a la valeur «Action».

Y a-t-il un moyen possible de le faire?

Anton
la source

Réponses:

176

__CLASS__renvoie toujours le nom de la classe dans laquelle il a été utilisé, donc cela n'aide pas beaucoup avec une méthode statique. Si la méthode n'est pas statique, vous pouvez simplement utiliser get_class ($ this). par exemple

class Action {
    public function n(){
        echo get_class($this);
    }

}

class MyAction extends Action {

}

$foo=new MyAction;

$foo->n(); //displays 'MyAction'

Liaisons statiques tardives, disponibles en PHP 5.3+

Maintenant que PHP 5.3 est publié, vous pouvez utiliser des liaisons statiques tardives , qui vous permettent de résoudre la classe cible pour un appel de méthode statique au moment de l'exécution plutôt que lors de sa définition.

Bien que la fonctionnalité n'introduise pas de nouvelle constante magique pour vous indiquer le nom de classe par lequel vous avez été appelé, elle fournit une nouvelle fonction, get_called_class (), qui peut vous indiquer le nom de la classe dans laquelle une méthode statique a été appelée. Voici un exemple:

Class Action {
    public static function n() {
        return get_called_class();
    }
}


class MyAction extends Action {

}


echo MyAction::n(); //displays MyAction
Paul Dixon
la source
Le seul problème pour l'OP est que la fonctionnalité n'est pas encore disponible. PHP 5.3 est encore en version bêta.
Ionuț G. Stan
3
@Paul, merci! Vous venez de sauver ma journée ... ou ma nuit avec get_called_class():)
Marecky
1
Je souhaite que quelqu'un puisse m'aider avec un problème similaire . Le script PHP meurt en silence lors de l'exécution new static();depuis l'intérieur d'une méthode statique privée (en utilisant xampp sous windows et php> 5.5). :s
Stphane
$ foo = new MyAction; echo get_class ($ foo); Cela imprime également MyAction.
sammry
40

Depuis la version 5.5, vous pouvez utiliser un classmot-clé pour la résolution du nom de classe , ce qui serait beaucoup plus rapide que d'effectuer des appels de fonction. Fonctionne également avec les interfaces.

// C extends B extends A

static::class  // MyNamespace\ClassC when run in A
self::class    // MyNamespace\ClassA when run in A
parent::class  // MyNamespace\ClassB when run in C
MyClass::class // MyNamespace\MyClass
Ian Bytchek
la source
16

Ce n'est pas la solution idéale, mais cela fonctionne sur PHP <5.3.0.

Le code a été copié depuis septuro.com

if(!function_exists('get_called_class')) {
    class class_tools {
        static $i = 0;
        static $fl = null;

        static function get_called_class() {
            $bt = debug_backtrace();

            if (self::$fl == $bt[2]['file'].$bt[2]['line']) {
                self::$i++;
            } else {
                self::$i = 0;
                self::$fl = $bt[2]['file'].$bt[2]['line'];
            }

            $lines = file($bt[2]['file']);

            preg_match_all('/([a-zA-Z0-9\_]+)::'.$bt[2]['function'].'/',
                $lines[$bt[2]['line']-1],
                $matches);

            return $matches[1][self::$i];
        }
    }

    function get_called_class() {
        return class_tools::get_called_class();
    }
}
Jrgns
la source
2
class MainSingleton { 
  private static $instances = array(); 
  private static function get_called_class() {
    $t = debug_backtrace();
    return $t[count($t)-1]["class"];
  }  

  public static function getInstance() { 
    $class = self::get_called_class();
    if(!isset(self::$instances[$class]) ) { 
      self::$instances[$class] = new $class; 
    } 
    return self::$instances[$class]; 
  } 

}

class Singleton extends MainSingleton { 
  public static function getInstance()
  {
    return parent::getInstance();
  }     
  protected function __construct() { 
    echo "A". PHP_EOL; 
  } 

  protected function __clone() {} 

  public function test() { 
    echo " * test called * "; 
  } 
} 

Singleton::getInstance()->test(); 
Singleton::getInstance()->test();
Lulu
la source
0

Il n'y a aucun moyen, dans les versions PHP disponibles, de faire ce que vous voulez. La solution de Paul Dixon est la seule. Je veux dire, l'exemple de code, car la fonctionnalité de liaison statique tardive dont il parle est disponible à partir de PHP 5.3, qui est en version bêta.

Ionuț G. Stan
la source
0

(PHP 5> = 5.3.0, PHP 7)
get_called_class - Le nom de la classe "Late Static Binding"

<?php

class Model
{
  public static function find()
  {
    return get_called_class();
  }
}

class User extends Model
{
}


echo User::find();

ce lien pourrait être utile

Biswajit Biswas
la source