Kann ich CONSTs für eine PHP-Klasse definieren lassen?

140

Ich habe mehrere CONSTs für einige Klassen definiert und möchte eine Liste von ihnen erhalten. Beispielsweise:

class Profile {
    const LABEL_FIRST_NAME = "First Name";
    const LABEL_LAST_NAME = "Last Name";
    const LABEL_COMPANY_NAME = "Company";
}

Gibt es eine Möglichkeit, eine Liste der in der ProfileKlasse definierten CONSTs zu erhalten ? Soweit ich das beurteilen kann, reicht die nächstgelegene Option ( get_defined_constants()) nicht aus.

Was ich eigentlich brauche, ist eine Liste der konstanten Namen - so etwas wie das:

array('LABEL_FIRST_NAME',
    'LABEL_LAST_NAME',
    'LABEL_COMPANY_NAME')

Oder:

array('Profile::LABEL_FIRST_NAME', 
    'Profile::LABEL_LAST_NAME',
    'Profile::LABEL_COMPANY_NAME')

Oder auch:

array('Profile::LABEL_FIRST_NAME'=>'First Name', 
    'Profile::LABEL_LAST_NAME'=>'Last Name',
    'Profile::LABEL_COMPANY_NAME'=>'Company')
Brock Boland
quelle
Sie können dies durch Reflektion tun . Suchen Sie auf dieser Seite nach "Klassenkonstanten drucken", um ein Beispiel anzuzeigen.
n3rd
Mit Reflection und einer ReflectionClass auf Cl können Sie die Funktion getConstants nz.php.net/manual/en/class.reflectionclass.php
Tim Ebenezer

Antworten:

245

Sie können hierfür Reflection verwenden . Beachten Sie, dass Sie, wenn Sie dies häufig tun, möglicherweise das Zwischenspeichern des Ergebnisses prüfen möchten.

<?php
class Profile {
    const LABEL_FIRST_NAME = "First Name";
    const LABEL_LAST_NAME = "Last Name";
    const LABEL_COMPANY_NAME = "Company";
}


$refl = new ReflectionClass('Profile');
print_r($refl->getConstants());

Ausgabe:

Array
(
    'LABEL_FIRST_NAME' => 'First Name',
    'LABEL_LAST_NAME' => 'Last Name',
    'LABEL_COMPANY_NAME' => 'Company'
)
Tom Haigh
quelle
4
Zwei kleinere NBs: Erstens kann in 5.3 Profiledas Argument für den Reflektorkonstruktor ohne Anführungszeichen (ein einfacher Klassenname) verwendet werden. Zweitens, um ganz klar zu sein, sind die Schlüssel des resultierenden Arrays Zeichenfolgen und keine Konstanten, wie die Formatierung hier vermuten lässt. (Erwähnenswert nur, da das fn nicht dokumentiert ist .)
Benji XVI
11
@Benji XVI Wenn Sie in 5.3 Benachrichtigungen aktiviert haben, können Sie diese Profileohne Anführungszeichen nicht verwenden, da der folgende Fehler angezeigt wird: Hinweis: Verwendung eines undefinierten konstanten Profils - angenommenes 'Profil'. Also schlage ich vor, die Anführungszeichen 'Profile'
beizubehalten
10
Es ist gut, konstantenbezogene Logik innerhalb der Klasse zu definieren, sodass Sie das Konstruktorargument nicht fest codieren müssen, sondern __CLASS__stattdessen verwenden müssen.
Luke Adamczewski
7
new ReflectionClass(Profile::class)funktioniert auch gut
mtizziani
@mtizziani wahr, aber achten Sie auf Namespaces! Angenommen, Sie haben einen Namespace Citymit Klasse B- es B::classwürde gut funktionieren, aber wenn Sie diese im zB Namespace verwenden würden Jungle- würde ein Aufruf B::classohne Namespace usedazu führen Jungle\B(obwohl Jungle überhaupt kein B hat!)
jave.web
22

Dies

 $reflector = new ReflectionClass('Status');
 var_dump($reflector->getConstants());
Wrikken
quelle
1
+1 Dies wäre es, da ich keine eingebauten prozeduralen PHP-Funktionen zum Abrufen von Klassenkonstanten finden kann, was ein bisschen schade ist.
BoltClock
1
Wahrscheinlich, weil es wenig nötig ist. Das OP möchte möglicherweise eine Metakonfiguration durchführen, indem es typesas festlegt all constants this class has, was in den meisten Fällen und meiner Meinung nach besser mit Vererbung oder einer statischen Arrayvariablen mit den Typen bedient werden kann (wobei Platz für Konstanten mit anderen Bedeutungen bleibt /). verwenden).
Wrikken
16

Verwenden Sie token_get_all () . Nämlich:

<?php
header('Content-Type: text/plain');

$file = file_get_contents('Profile.php');
$tokens = token_get_all($file);

$const = false;
$name = '';
$constants = array();
foreach ($tokens as $token) {
    if (is_array($token)) {
        if ($token[0] != T_WHITESPACE) {
            if ($token[0] == T_CONST && $token[1] == 'const') {
                $const = true;
                $name = '';
            } else if ($token[0] == T_STRING && $const) {
                $const = false;
                $name = $token[1];
            } else if ($token[0] == T_CONSTANT_ENCAPSED_STRING && $name) {
                $constants[$name] = $token[1];
                $name = '';
            }
        }
    } else if ($token != '=') {
        $const = false;
        $name = '';
    }
}

foreach ($constants as $constant => $value) {
    echo "$constant = $value\n";
}
?>

Ausgabe:

LABEL_FIRST_NAME = "First Name"
LABEL_LAST_NAME = "Last Name"
LABEL_COMPANY_NAME = "Company"
Cletus
quelle
1
+1, obwohl ich sagen würde, dass dies ein ausgezeichneter Zeitpunkt ist, um Reflection zu verwenden, wie von anderen Postern erwähnt, ist es auch wichtig, die Funktionsweise "unter der Haube" zu verstehen und in der Lage zu sein, auf sie zu verzichten oder sie gegebenenfalls zu replizieren. Gute Show.
Abgebrochen
1
Wenn Sie nicht möchten, dass Ihre Klasse in den Speicher geladen wird, ist token_get_all eine fantastische Alternative. Es ist VIEL schneller als Reflection und überfüllt den Prozessspeicher nicht, wenn Sie dies mit vielen Klassen tun müssen.
Harold
+1 für die tokenbasierte Lösung! Das Verständnis der tokenbasierten Analyse ist angesichts der Leistung ein Vergnügen ... und wie immer gibt es eine großartige Person, die zeigt, wie Konstanten über token_get_all () analysiert werden. Vielen Dank!
Mwatzer
Vermutlich wirkt sich dies nur auf die einzelne Datei aus und erbt keine Konstanten von übergeordneten Klassen. Tatsächlich kümmert sich diese Technik nicht einmal um die Klasse - sie gibt Ihnen alle Konstanten in der Datei, auch im globalen Bereich. Es ist jedoch ein großartiges Werkzeug zum Erkunden.
Jason
14

In PHP5 können Sie Reflection verwenden: (manuelle Referenz)

$class = new ReflectionClass('Profile');
$consts = $class->getConstants();
Parsingphase
quelle
13

Wenn Sie die ReflectionClass (PHP 5) verwenden können, lesen Sie die Kommentare in den PHP-Dokumenten:

function GetClassConstants($sClassName) {
    $oClass = new ReflectionClass($sClassName);
    return $oClass->getConstants();
}

Quelle ist hier.

mway
quelle
9

Verwenden Sie ReflectionClass und getConstants()geben Sie genau das, was Sie wollen:

<?php
class Cl {
    const AAA = 1;
    const BBB = 2;
}
$r = new ReflectionClass('Cl');
print_r($r->getConstants());

Ausgabe:

Array
(
    [AAA] => 1
    [BBB] => 2
)
Ben James
quelle
6

Merkmal mit statischer Methode - zur Rettung

Sieht so aus, als wäre es ein guter Ort, um Merkmale mit einer statischen Funktion zu verwenden, um die Klassenfunktionalität zu erweitern. Mit Traits können wir diese Funktionalität auch in jeder anderen Klasse implementieren, ohne denselben Code immer wieder neu schreiben zu müssen (bleiben Sie trocken).

Verwenden Sie unser benutzerdefiniertes 'ConstantExport'-Merkmal mit in der Profilklasse. Tun Sie dies für jede Klasse, für die Sie diese Funktionalität benötigen.

/**
 * ConstantExport Trait implements getConstants() method which allows 
 * to return class constant as an assosiative array
 */
Trait ConstantExport 
{
    /**
     * @return [const_name => 'value', ...]
     */
    static function getConstants(){
        $refl = new \ReflectionClass(__CLASS__);
        return $refl->getConstants();
    }
}

Class Profile 
{
    const LABEL_FIRST_NAME = "First Name";
    const LABEL_LAST_NAME = "Last Name";
    const LABEL_COMPANY_NAME = "Company";

    use ConstantExport;

}

VERWENDUNGSBEISPIEL

// So simple and so clean
$constList = Profile::getConstants(); 

print_r($constList); // TEST

AUSGÄNGE:

Array
(
    [LABEL_FIRST_NAME] => First Name
    [LABEL_LAST_NAME] => Last Name
    [LABEL_COMPANY_NAME] => Company
)
DevWL
quelle
5

Ja, du benutzt Reflexion . Schauen Sie sich die Ausgabe von an

<?
Reflection::export(new ReflectionClass('YourClass'));
?>

Das sollte Ihnen eine Vorstellung davon geben, was Sie sehen werden.

Chaos
quelle
4

Es ist praktisch, eine Methode in der Klasse zu haben, um ihre eigenen Konstanten zurückzugeben.
Sie können dies folgendermaßen tun:

class Profile {
    const LABEL_FIRST_NAME = "First Name";
    const LABEL_LAST_NAME = "Last Name";
    const LABEL_COMPANY_NAME = "Company";


    public static function getAllConsts() {
        return (new ReflectionClass(get_class()))->getConstants();
    }
}

// test
print_r(Profile::getAllConsts());
Luis Siquot
quelle
3

Warum setzen Sie sie nicht zunächst als Array in eine Klassenvariable? Erleichtert das Durchschleifen.

private $_data = array("production"=>0 ...);
Erkennen
quelle
2
Weil Arrays keine Konstanten sind? Wenn Sie etwas implementieren, das als Variable eine Konstante sein soll, besteht die Gefahr, dass es versehentlich geändert oder deaktiviert wird. Mit anderen Worten, Sie können sich nicht darauf verlassen, dass sie konstant bleiben.
GordonM
3

Eventuell mit Namespaces:

namespaces enums;
class enumCountries 
{
  const CountryAustria          = 1 ;
  const CountrySweden           = 24;
  const CountryUnitedKingdom    = 25;
}

namespace Helpers;
class Helpers
{
  static function getCountries()
  {
    $c = new \ReflectionClass('\enums\enumCountries');
    return $c->getConstants();
  }
}

print_r(\Helpers\Helpers::getCountries());
widerrufen
quelle
1
class Qwerty 
{
    const __COOKIE_LANG_NAME__ = "zxc";
    const __UPDATE_COOKIE__ = 30000;

    // [1]
    public function getConstants_(){

        return ['__COOKIE_LANG_NAME__' => self::__COOKIE_LANG_NAME__, 
                '__UPDATE_COOKIE__' => self::__UPDATE_COOKIE__]; 
    }    

    // [2]
    static function getConstantsStatic_(){

        return ['__COOKIE_LANG_NAME__' => self::__COOKIE_LANG_NAME__, 
                '__UPDATE_COOKIE__' => self::__UPDATE_COOKIE__]; 
    } 
}

// [1]
$objC = new Qwerty();
var_dump($objC->getConstants_());

// [2]
var_dump(Qwerty::getConstantsStatic_());
Юрий Светлов
quelle