Comment obtenir le nom de classe non qualifié (court) d'un objet?


153

Comment vérifier la classe d'un objet dans l'environnement d'espacement des noms PHP sans spécifier la classe d'espacement de noms complète.

Par exemple, supposons que j'ai une bibliothèque d'objets / Entité / Contrat / Nom.

Le code suivant ne fonctionne pas car get_class renvoie la classe d'espace de noms complète.

If(get_class($object) == 'Name') {
... do this ...
}

Le mot-clé namespace magic renvoie l'espace de noms actuel, ce qui ne sert à rien si l'objet testé a un autre espace de noms.

Je pourrais simplement spécifier le nom de classe complet avec les espaces de noms, mais cela semble verrouiller la structure du code. Aussi peu utile si je voulais changer l'espace de noms de manière dynamique.

Quelqu'un peut-il penser à un moyen efficace de le faire. Je suppose qu'une option est regex.


Cela semble presque inutile car différents espaces de noms pourraient avoir les mêmes noms de classe définis à l'intérieur, alors comment allez-vous gérer cela? Et c'est parce que le nom de classe qualifié complet est retourné dans votre échantillon
Alma Do

Je suis sur un appareil mobile, donc je ne peux pas soumettre une réponse décente, mais la solution est la réflexion, en particulier ReflectionClass :: getShortName - php.net/manual/en/reflectionclass.getshortname.php
lonesomeday

Pour les personnes recherchant une raison de vouloir ceci: cela peut être utile dans une fonction d'assistance dans une classe de base commune (c'est-à-dire que plusieurs espaces de noms ne sont jamais un problème dans cette situation).
Darren Cook

Réponses:


182

Vous pouvez le faire avec la réflexion. Plus précisément, vous pouvez utiliser la ReflectionClass::getShortNameméthode, qui obtient le nom de la classe sans son espace de noms.

Tout d'abord, vous devez créer une ReflectionClassinstance, puis appeler la getShortNameméthode de cette instance:

$reflect = new ReflectionClass($object);
if ($reflect->getShortName() === 'Name') {
    // do this
}

Cependant, je ne peux pas imaginer de nombreuses circonstances où cela serait souhaitable. Si vous voulez exiger que l'objet soit membre d'une certaine classe, la façon de le tester est avec instanceof. Si vous voulez une manière plus flexible de signaler certaines contraintes, la manière de le faire est d'écrire une interface et d'exiger que le code implémente cette interface. Encore une fois, la bonne façon de faire est avec instanceof. (Vous pouvez le faire avec ReflectionClass, mais les performances seraient bien pires.)


1
@ Greg.Forbes Car Tenantn'existe pas dans l'espace de noms actuel. Essayez à la var_dump($tenant instanceof \Library\Entity\People\Tenant)place. Découvrez également comment utiliser l' useopérateur et le concept général des espaces de noms PHP!
Lonesomeday

3
Je devais ajouter une barre oblique devant comme ça$reflect = new \ReflectionClass($object);
prograhammer

7
Je n'aime généralement pas faire beaucoup de vaudou ReflectionClass dans mon application car cela peut conduire à des résultats inattendus en cas de mauvaise utilisation (méthodes protégées devenant publiques, etc.). Vous pouvez utiliser un simple remplacement de chaîne sur les constantes magiques PHP au lieu: str_replace(__NAMESPACE__ . '\\', '', __CLASS__);. C'est aussi beaucoup plus rapide en termes de performances.
Franklin P Strube

2
@FranklinPStrube Sauf si je manque quelque chose, cela obtient le nom court de la classe actuelle, plutôt que la classe de l'objet. Je conviens que l'utilisation de la réflexion signifie généralement que vous faites le mal.
Lonesomeday

1
De nombreuses personnes utilisent Reflections pour les remplacements de visibilité des membres, ce qui est MAUVAIS. Ne faites pas cela! Mais affirmer que l'utilisation des réflexions en général est du vaudou et le faire mal donne aux gens une mauvaise impression. Vous ne devez pas les éviter, vous devez les comprendre et savoir quand ils sont bénéfiques et à quel niveau d'abstraction.
Vanja D.

131

(new \ReflectionClass($obj))->getShortName(); est la meilleure solution en termes de performances.

J'étais curieux de savoir laquelle des solutions proposées était la plus rapide, j'ai donc préparé un petit test.

Résultats

Reflection: 1.967512512207 s ClassA
Basename:   2.6840535163879 s ClassA
Explode:    2.6507515668869 s ClassA

Code

namespace foo\bar\baz;

class ClassA{
    public function getClassExplode(){
        return explode('\\', static::class)[0];
    }

    public function getClassReflection(){
        return (new \ReflectionClass($this))->getShortName();
    }

    public function getClassBasename(){
        return basename(str_replace('\\', '/', static::class));
    }
}

$a = new ClassA();
$num = 100000;

$rounds = 10;
$res = array(
    "Reflection" => array(),
    "Basename" => array(),
    "Explode" => array(),
);

for($r = 0; $r < $rounds; $r++){

    $start = microtime(true);
    for($i = 0; $i < $num; $i++){
        $a->getClassReflection();
    }
    $end = microtime(true);
    $res["Reflection"][] = ($end-$start);

    $start = microtime(true);
    for($i = 0; $i < $num; $i++){
        $a->getClassBasename();
    }
    $end = microtime(true);
    $res["Basename"][] = ($end-$start);

    $start = microtime(true);
    for($i = 0; $i < $num; $i++){
        $a->getClassExplode();
    }
    $end = microtime(true);
    $res["Explode"][] = ($end-$start);
}

echo "Reflection: ".array_sum($res["Reflection"])/count($res["Reflection"])." s ".$a->getClassReflection()."\n";
echo "Basename: ".array_sum($res["Basename"])/count($res["Basename"])." s ".$a->getClassBasename()."\n";
echo "Explode: ".array_sum($res["Explode"])/count($res["Explode"])." s ".$a->getClassExplode()."\n";

Les résultats m'ont surpris. Je pensais que la solution exploser serait le moyen le plus rapide d'aller ...


1
Très bonne réponse. J'utilisais le même code mais j'ai obtenu un résultat différent (Macbook Pro i7, 16 Go de RAM). Réflexion: 0,382, Nom de base: 0,380, Explosion: 0,399. Je pense que cela dépend de votre système ce qui est le mieux ...
Tobias Nyholm

4
Exécutez PHP 10 000 fois avec ce code et vous obtenez un meilleur résultat. Ce qui précède peut extraire la réflexion d'un pool, mais ce n'est pas le comportement habituel des applications. Ils n'en ont besoin qu'une ou deux fois.
LeMike

6
Je me demande si ce test est vrai lors de l'instanciation d'une ReflectionClass sur un objet plus substantiel que le petit objet de classe A dans votre test ...
Joe Green

2
l'exécution d'une seule itération au lieu de 100000 donne un résultat très différent: Réflexion: 1.0967254638672 100000th / s Nom de base de ClassA: 0.81062316894531 100000th / s ClassA Explode: 0.50067901611328 100000th / s ClassA
mcmurphy

1
exploser ('\\', static :: class) [0]? ne retourne-t-il pas la première partie de l'espace de noms? devrait retourner la dernière partie, pas la première
2oppin

86

J'ai ajouté substr au test de https://stackoverflow.com/a/25472778/2386943 et c'est la manière la plus rapide que j'ai pu tester (CentOS PHP 5.3.3, Ubuntu PHP 5.5.9) à la fois avec un i5.

$classNameWithNamespace=get_class($this);
return substr($classNameWithNamespace, strrpos($classNameWithNamespace, '\\')+1);

Résultats

Reflection: 0.068084406852722 s ClassA
Basename: 0.12301609516144 s ClassA
Explode: 0.14073524475098 s ClassA
Substring: 0.059865570068359 s ClassA 

Code

namespace foo\bar\baz;
class ClassA{
  public function getClassExplode(){
    $c = array_pop(explode('\\', get_class($this)));
    return $c;
  }

  public function getClassReflection(){
    $c = (new \ReflectionClass($this))->getShortName();
    return $c;
  }

  public function getClassBasename(){
    $c = basename(str_replace('\\', '/', get_class($this)));
    return $c;
  }

  public function getClassSubstring(){
    $classNameWithNamespace = get_class($this);
    return substr($classNameWithNamespace, strrpos($classNameWithNamespace, '\\')+1);
  }
}

$a = new ClassA();
$num = 100000;

$rounds = 10;
$res = array(
    "Reflection" => array(),
    "Basename" => array(),
    "Explode" => array(),
    "Substring" => array()
);

for($r = 0; $r < $rounds; $r++){

  $start = microtime(true);
  for($i = 0; $i < $num; $i++){
    $a->getClassReflection();
  }
  $end = microtime(true);
  $res["Reflection"][] = ($end-$start);

  $start = microtime(true);
  for($i = 0; $i < $num; $i++){
    $a->getClassBasename();
  }
  $end = microtime(true);
  $res["Basename"][] = ($end-$start);

  $start = microtime(true);
  for($i = 0; $i < $num; $i++){
    $a->getClassExplode();
  }
  $end = microtime(true);
  $res["Explode"][] = ($end-$start);

  $start = microtime(true);
  for($i = 0; $i < $num; $i++){
    $a->getClassSubstring();
  }
  $end = microtime(true);
  $res["Substring"][] = ($end-$start);
}

echo "Reflection: ".array_sum($res["Reflection"])/count($res["Reflection"])." s ".$a->getClassReflection()."\n";
echo "Basename: ".array_sum($res["Basename"])/count($res["Basename"])." s ".$a->getClassBasename()."\n";
echo "Explode: ".array_sum($res["Explode"])/count($res["Explode"])." s ".$a->getClassExplode()."\n";
echo "Substring: ".array_sum($res["Substring"])/count($res["Substring"])." s ".$a->getClassSubstring()."\n";

== MISE À JOUR ==

Comme mentionné dans les commentaires de @MrBandersnatch, il existe un moyen encore plus rapide de le faire:

return substr(strrchr(get_class($this), '\\'), 1);

Voici les résultats des tests mis à jour avec "SubstringStrChr" (enregistre jusqu'à environ 0,001 s):

Reflection: 0.073065280914307 s ClassA
Basename: 0.12585079669952 s ClassA
Explode: 0.14593172073364 s ClassA
Substring: 0.060415267944336 s ClassA
SubstringStrChr: 0.059880912303925 s ClassA

5
Juste parce que nous énumérons pour l'efficacité, j'ai trouvé que c'était la comparaison la plus rapide du test fourni dans cette solution substr (strrchr (get_class ($ obj), '\\'), 1); Réflexion: 0,084223914146423 s ClassA - Nom de base: 0,13206427097321 s ClassA - Explode: 0,15331919193268 s ClassA - Sous-chaîne: 0,068068099021912 s ClassA - Strrchar: 0,06472008228302 s ClassA -
ctatro85

Je viens de tomber sur ce fil et j'ai ajouté une référence supplémentaire à tester str_replace(__NAMESPACE__ . '\\', '', __CLASS__);. Les résultats sur une machine virtuelle faible ont montré qu'elle était presque deux fois plus rapide que tout cela. php -f bench.php Reflection: 0.44037771224976 s ClassA Basename: 0.48089025020599 s ClassA Explode: 0.54955270290375 s ClassA Substring: 0.38200764656067 s ClassA Frank's Custom Benchmark: 0.22782742977142 s ClassA
Franklin P Strube

1
@MrBandersnatch vous avez raison. J'ai testé votre solution et cela m'a fait gagner environ 0,001 s. J'ai mis à jour ma réponse avec la vôtre!
MaBi

3
Attention: ce code ne fonctionne pas avec les classes dans l'espace de noms global (ie: leur nom complet est égal à leur nom court)! Je conseil à quelque chose comme test: if ($pos = strrchr(static::class, '\\')) { .. } else { ... }.
Tristan Jahier

1
Pour que cela fonctionne également dans l'espace de noms global, ajoutez simplement le nom de la classe avec une barre oblique inverse :) - c'est-à-dire:$classNameShort = substr(strrchr('\\' . get_class($this), '\\'), 1);
rosell.dk

26

Voici un moyen plus simple de le faire si vous utilisez le framework PHP Laravel:

<?php

// usage anywhere
// returns HelloWorld
$name = class_basename('Path\To\YourClass\HelloWorld');

// usage inside a class
// returns HelloWorld
$name = class_basename(__CLASS__);

8
Ce n'est pas une fonction PHP intégrée, cela ressemble à une fonction d'assistance fournie par laravel.
Steve Buzonas

7
Je pense qu'il a dit ça
Scott

4
Merci, j'utilise Laravel et cette réponse m'a fait gagner beaucoup de temps.
Jeremy Wadhams


18

J'utilise ceci:

basename(str_replace('\\', '/', get_class($object)));

Vous pouvez également essayer: $ className = exploser ('\\', basename (get_class ($ this))); $ className = array_pop ($ className); pour obtenir le nom de classe simple. Ou utilisez substr.
dompie

13
Fonctionne uniquement sous Windows Sous Windows, la barre oblique (/) et la barre oblique inverse () sont utilisées comme séparateur de répertoire. Dans d'autres environnements, c'est la barre oblique (/) php.net/manual/en/function.basename.php
OzzyCzech

Je l'ai réparé maintenant. Merci, @OzzyCzech.
Theodore R. Smith

1
@OzzyCzech Je viens de rencontrer cela en passant de Windows à Ubuntu .... exaspérant. Bloqué en utilisant la solution mentionnée dans la mise à jour de MaBi.
Chris Baker

@OzzyCzech Comment se fait-il que fonctionne uniquement sous Windows? la question concernait le nom complet de l'espace de noms si je ne me suis pas trompé il y a également des années, et les espaces de noms ne sont pas spécifiques au système d'exploitation, et toujours avec une barre oblique inverse comme le séparateur de répertoire Windows.
FantomX1

16

Pour obtenir le nom court en une seule ligne (depuis PHP 5.4 ):

echo (new ReflectionClass($obj))->getShortName();

C'est une approche propre et raisonnable rapide .


1
Je me demande comment cela se compare à une extraction de chaîne dans les benchmarks. Il semble que ce serait beaucoup plus lent.
Contact non vérifié

12

Je me suis retrouvé dans une situation unique où instanceofje ne pouvais pas être utilisé (en particulier les traits d'espacement de noms) et j'avais besoin du nom court de la manière la plus efficace possible, alors j'ai fait un petit benchmark par moi-même. Il comprend toutes les différentes méthodes et variations des réponses à cette question.

$bench = new \xori\Benchmark(1000, 1000);     # https://github.com/Xorifelse/php-benchmark-closure
$shell = new \my\fancy\namespace\classname(); # Just an empty class named `classname` defined in the `\my\fancy\namespace\` namespace

$bench->register('strrpos', (function(){
    return substr(static::class, strrpos(static::class, '\\') + 1);
})->bindTo($shell));

$bench->register('safe strrpos', (function(){
    return substr(static::class, ($p = strrpos(static::class, '\\')) !== false ? $p + 1 : 0);
})->bindTo($shell));

$bench->register('strrchr', (function(){
    return substr(strrchr(static::class, '\\'), 1);
})->bindTo($shell));

$bench->register('reflection', (function(){
    return (new \ReflectionClass($this))->getShortName();
})->bindTo($shell));

$bench->register('reflection 2', (function($obj){
    return $obj->getShortName();
})->bindTo($shell), new \ReflectionClass($shell));

$bench->register('basename', (function(){
    return basename(str_replace('\\', '/', static::class));
})->bindTo($shell));

$bench->register('explode', (function(){
    $e = explode("\\", static::class);
    return end($e);
})->bindTo($shell));

$bench->register('slice', (function(){
    return join('',array_slice(explode('\\', static::class), -1));
})->bindTo($shell));    

print_r($bench->start());

Une liste de l'ensemble du résultat est ici mais voici les faits saillants:

  • Si vous allez à la réflexion de l' utilisation de toute façon, à l' aide $obj->getShortName()est la méthode la plus rapide cependant ; en utilisant la réflexion uniquement pour obtenir le nom court, c'est presque la méthode la plus lente.
  • 'strrpos'peut renvoyer une valeur erronée si l'objet n'est pas dans un espace de noms, alors que 'safe strrpos'c'est un tout petit peu plus lent, je dirais que c'est le gagnant.
  • Pour rendre 'basename'compatible entre Linux et Windows, vous devez utiliser str_replace()ce qui fait de cette méthode la plus lente de toutes.

Un tableau de résultats simplifié, la vitesse est mesurée par rapport à la méthode la plus lente:

+-----------------+--------+
| registered name | speed  |
+-----------------+--------+
| reflection 2    | 70.75% |
| strrpos         | 60.38% |
| safe strrpos    | 57.69% |
| strrchr         | 54.88% |
| explode         | 46.60% |
| slice           | 37.02% |
| reflection      | 16.75% |
| basename        | 0.00%  |
+-----------------+--------+

8

Vous pouvez utiliser explodepour séparer l'espace de noms et endpour obtenir le nom de la classe:

$ex = explode("\\", get_class($object));
$className = end($ex);

7

Voie Yii

\yii\helpers\StringHelper::basename(get_class($model));

Yii utilise cette méthode dans son générateur de code Gii

Documentation de la méthode

Cette méthode est similaire à la fonction php basename () sauf qu'elle traitera à la fois \ et / comme des séparateurs de répertoires, indépendamment du système d'exploitation. Cette méthode a été principalement créée pour fonctionner sur les espaces de noms php. Lorsque vous travaillez avec des chemins de fichiers réels, basename () de php devrait fonctionner correctement pour vous. Remarque: cette méthode ne connaît pas le système de fichiers réel ou les composants du chemin tels que "..".

Plus d'information:

https://github.com/yiisoft/yii2/blob/master/framework/helpers/BaseStringHelper.php http://www.yiiframework.com/doc-2.0/yii-helpers-basestringhelper.html#basename()-detail


Bienvenue dans Stack Overflow. Veuillez fournir plus d'informations pour votre réponse. Qu'est-ce que cela fait et comment peut-on l'utiliser.
Jens

1
Cela a fonctionné pour moi sous Windows mais pas sous Linux, peut-être parce que les espaces de noms sont sous la forme de barres obliques inverses des répertoires Windows «\», alors que Linux basename considère les séparateurs de répertoires par des barres obliques «/». J'ai donc travaillé avec strtr. basename (strtr ($ class, '\\', '/'))
FantomX1

6

Voici une solution simple pour PHP 5.4+

namespace {
    trait Names {
        public static function getNamespace() {
            return implode('\\', array_slice(explode('\\', get_called_class()), 0, -1));
        }

        public static function getBaseClassName() {
            return basename(str_replace('\\', '/', get_called_class()));
        }
    }
}

Quel sera le retour?

namespace x\y\z {
    class SomeClass {
        use \Names;
    }

    echo \x\y\z\SomeClass::getNamespace() . PHP_EOL; // x\y\z
    echo \x\y\z\SomeClass::getBaseClassName() . PHP_EOL; // SomeClass
}

Le nom de classe et l'espace de noms étendus fonctionnent bien pour:

namespace d\e\f {

    class DifferentClass extends \x\y\z\SomeClass {

    }

    echo \d\e\f\DifferentClass::getNamespace() . PHP_EOL; // d\e\f
    echo \d\e\f\DifferentClass::getBaseClassName() . PHP_EOL; // DifferentClass
}

Qu'en est-il de la classe dans l'espace de noms global?

namespace {

    class ClassWithoutNamespace {
        use \Names;
    }

    echo ClassWithoutNamespace::getNamespace() . PHP_EOL; // empty string
    echo ClassWithoutNamespace::getBaseClassName() . PHP_EOL; // ClassWithoutNamespace
}

3

Si vous avez besoin de connaître le nom de la classe qui a été appelée depuis l'intérieur d'une classe et que vous ne voulez pas l'espace de noms, vous pouvez utiliser celui-ci

$calledClass = get_called_class();
$name = strpos($calledClass, '\\') === false ?
    $calledClass : substr($calledClass, strrpos($calledClass, '\\') + 1);

C'est génial lorsque vous avez une méthode dans une classe qui est étendue par d'autres classes. De plus, cela fonctionne également si les espaces de noms ne sont pas du tout utilisés.

Exemple:

<?php
namespace One\Two {
    class foo
    {
        public function foo()
        {
            $calledClass = get_called_class();
            $name = strpos($calledClass, '\\') === false ?
                $calledClass : substr($calledClass, strrpos($calledClass, '\\') + 1);

            var_dump($name);
        }
    }
}

namespace Three {
    class bar extends \One\Two\foo
    {
        public function bar()
        {
            $this->foo();
        }
    }
}

namespace {
    (new One\Two\foo)->foo();
    (new Three\bar)->bar();
}

// test.php:11:string 'foo' (length=3)
// test.php:11:string 'bar' (length=3)

2

Sur la base de la réponse de @MaBi, j'ai fait ceci:

trait ClassShortNameTrait
{
    public static function getClassShortName()
    {
        if ($pos = strrchr(static::class, '\\')) {
            return substr($pos, 1);
        } else {
            return static::class;
        }
    }
}

Que vous pouvez utiliser comme ça:

namespace Foo\Bar\Baz;

class A
{
    use ClassShortNameTrait;
}

A::classrevient Foo\Bar\Baz\A, mais A::getClassShortName()revient A.

Fonctionne pour PHP> = 5.5.


2

Je sais que c'est un vieil article mais c'est ce que j'utilise - Plus rapide que tout ce qui est posté ci-dessus, appelez simplement cette méthode depuis votre classe, beaucoup plus rapidement que d'utiliser Reflection

namespace Foo\Bar\Baz;

class Test {
    public function getClass() {
        return str_replace(__NAMESPACE__.'\\', '', static::class);
    }
}

Malheureusement, cela ne fonctionne que si vous l'appelez dans la classe dont vous voulez le nom, pas sur n'importe quel nom de classe sous forme de chaîne.
jurchiks

1

Trouvé sur la page de documentation de get_class , où il a été posté par moi à nwhiting dot com .

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];
}

Mais l'idée des espaces de noms est de structurer votre code. Cela signifie également que vous pouvez avoir des classes avec le même nom dans plusieurs espaces de noms. Donc, théoriquement, l'objet que vous passez pourrait avoir le nom de classe (dépouillé), tout en étant un objet totalement différent de celui que vous attendez.

En plus de cela, vous voudrez peut-être rechercher une classe de base spécifique , auquel cas get_classne fait pas du tout l'affaire. Vous voudrez peut-être vérifier l'opérateur instanceof.


1

Vous pouvez obtenir un résultat inattendu lorsque la classe n'a pas d'espace de noms. Ie get_classretourne Foo, alors $baseClassserait oo.

$baseClass = substr(strrchr(get_class($this), '\\'), 1);

Cela peut facilement être corrigé en préfixant get_classavec une barre oblique inverse:

$baseClass = substr(strrchr('\\'.get_class($this), '\\'), 1);

Désormais, les classes sans espace de noms renverront également la bonne valeur.


1

Une bonne vieille regex semble être plus rapide que la plupart des méthodes précédentes montrées:

// both of the below calls will output: ShortClassName

echo preg_replace('/.*\\\\/', '', 'ShortClassName');
echo preg_replace('/.*\\\\/', '', 'SomeNamespace\SomePath\ShortClassName');

Cela fonctionne donc même lorsque vous fournissez un nom de classe court ou un nom de classe complet (canonique).

Ce que fait l'expression régulière, c'est qu'il consomme tous les caractères précédents jusqu'à ce que le dernier séparateur soit trouvé (qui est également consommé). La chaîne restante sera donc le nom court de la classe.

Si vous souhaitez utiliser un séparateur différent (par exemple. /), Utilisez simplement ce séparateur à la place. N'oubliez pas d'échapper la barre oblique inverse (c'est-à-dire. \) Et également le caractère de motif (c'est-à-dire. /) Dans le modèle d'entrée.


1

Parce que "ReflectionClass" peut dépendre de la version, utilisez simplement ce qui suit:

if(class_basename(get_class($object)) == 'Name') {
... do this ...
}

ou même clair

if(class_basename(ClassName::class) == 'ClassName') {
... do this ...
}

0

Citant php.net:

Sous Windows, la barre oblique (/) et la barre oblique inverse () sont utilisées comme séparateur de répertoire. Dans d'autres environnements, il s'agit de la barre oblique (/).

Sur la base de ces informations et de l'expansion de la réponse arzzzen, cela devrait fonctionner sur les systèmes Windows et Nix *:

<?php

if (basename(str_replace('\\', '/', get_class($object))) == 'Name') {
    // ... do this ...
}

Remarque: j'ai fait un benchmark de ReflectionClasscontre basename+str_replace+get_classet l'utilisation de la réflexion est environ 20% plus rapide que l'utilisation de l'approche du nom de base, mais YMMV.


0

La solution la plus rapide et la plus simple qui fonctionne dans n'importe quel environnement est:

<?php

namespace \My\Awesome\Namespace;

class Foo {

  private $shortName;

  public function fastShortName() {
    if ($this->shortName === null) {
      $this->shortName = explode("\\", static::class);
      $this->shortName = end($this->shortName);
    }
    return $this->shortName;
  }

  public function shortName() {
    return basename(strtr(static::class, "\\", "/"));
  }

}

echo (new Foo())->shortName(); // "Foo"

?>

1
C'est pourquoi j'aurais aimé que PHP ait des opérateurs d'information de classe internes. Instancier un réflecteur externe pour faire ce qui devrait être aussi simple que $Object->__class->getShortName()vraiment me fait chier à propos de PHP. Votre approche fonctionne, mais maintenant vous mettez des méthodes concrètes dans vos classes juste pour exposer ce qui devrait être une construction de langage.
AgmLauncher

PHP sans fonctions «concrètes» (ou devrions-nous les appeler procédurales) est impossible. Attendons PHP 6 (enfin, si jamais ça arrive).
Fleshgrinder le

0
$shortClassName = join('',array_slice(explode('\\', $longClassName), -1));

0

Si vous supprimez simplement les espaces de nom et que vous voulez quelque chose après le dernier \ dans un nom de classe avec un espace de noms (ou juste le nom s'il n'y a pas de '\'), vous pouvez faire quelque chose comme ceci:

$base_class = preg_replace('/^([\w\\\\]+\\\\)?([^\\\\]+)$/', '$2', get_class($myobject));

Fondamentalement, c'est regex pour obtenir n'importe quelle combinaison de caractères ou de barres obliques inverses vers le haut et jusqu'à la dernière barre oblique inverse, puis de ne renvoyer que les caractères sans barre oblique inverse jusqu'à la fin de la chaîne. Ajout du? après le premier regroupement, cela signifie que si la correspondance de modèle n'existe pas, elle renvoie simplement la chaîne complète.


0

Plus rapide que j'ai trouvé ici pour PHP 7.2leUbubntu 18.04

preg_replace('/^(\w+\\\)*/', '', static::class)
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.