Posso definir os CONSTs em uma classe PHP?

140

Eu tenho vários CONSTs definidos em algumas classes e quero obter uma lista delas. Por exemplo:

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

Existe alguma maneira de obter uma lista dos CONSTs definidos na Profileclasse? Até onde eu sei, a opção mais próxima ( get_defined_constants()) não funciona.

O que eu realmente preciso é de uma lista dos nomes constantes - algo como isto:

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

Ou:

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

Ou até:

array('Profile::LABEL_FIRST_NAME'=>'First Name', 
    'Profile::LABEL_LAST_NAME'=>'Last Name',
    'Profile::LABEL_COMPANY_NAME'=>'Company')
Brock Boland
fonte
Você pode fazer isso usando reflexão . Procure por "Imprimir constantes da classe" nessa página para ver um exemplo.
N3rd 5/06
Usando Reflection, e uma ReflectionClass em Cl, você pode usar a função getConstants nz.php.net/manual/en/class.reflectionclass.php
Tim Ebenezer

Respostas:

245

Você pode usar o Reflection para isso. Observe que, se você estiver fazendo isso muito, poderá querer armazenar em cache o resultado.

<?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());

Resultado:

Array
(
    'LABEL_FIRST_NAME' => 'First Name',
    'LABEL_LAST_NAME' => 'Last Name',
    'LABEL_COMPANY_NAME' => 'Company'
)
Tom Haigh
fonte
4
Dois RNs menores: primeiro, em 5.3, Profilepodem ser usados ​​como argumento para o construtor refletor, sem aspas (um nome simples de classe); segundo, para ficar completamente claro, as chaves da matriz resultante são cadeias de caracteres, não constantes, como a formatação aqui pode sugerir. (Vale a pena mencionar apenas como o fn é não documentada .)
Benji XVI
11
@Benji XVI Na versão 5.3, se você tiver avisos ativados, não poderá usar Profilesem as aspas, pois mostrará o seguinte erro: Aviso: Uso de perfil constante indefinido - assumido 'Perfil'. Então, sugiro manter as aspas'Profile'
Toneplex
10
É bom definir a lógica relacionada às constantes dentro da classe, para que você não precise codificar o argumento do construtor, mas use-o __CLASS__.
27413 Luke Lukeczewski
7
new ReflectionClass(Profile::class)funciona bem também
mtizziani 22/09/16
@mtizziani true, mas esteja ciente dos namespaces! Digamos que você tenha um namespace Citycom classe B- B::classele funcionaria bem, mas se você os usasse, por exemplo, namespace Jungle- a chamada para B::classlá sem incluí-lo useresultaria em Jungle\B(mesmo que o Jungle NÃO tenha B de todo!)
jave.web
22

este

 $reflector = new ReflectionClass('Status');
 var_dump($reflector->getConstants());
Wrikken
fonte
1
+1 Seria uma vez que eu não consigo encontrar nenhuma função PHP processual interna para obter constantes de classe, o que é uma pena.
BoltClock
1
Provavelmente porque há pouca necessidade disso. O OP pode querer fazer uma meta-configuração definindo typescomo all constants this class has, que na maioria dos casos, e na minha opinião limitada concedida, provavelmente é melhor servido com herança ou uma variável de matriz estática com os tipos (deixando espaço para constantes com outros significados / usar).
Wrikken 15/10/10
16

Use token_get_all () . Nomeadamente:

<?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";
}
?>

Resultado:

LABEL_FIRST_NAME = "First Name"
LABEL_LAST_NAME = "Last Name"
LABEL_COMPANY_NAME = "Company"
cleto
fonte
1
+1, mesmo que eu diria que este é um excelente momento para usar o Reflection, como mencionado em outros pôsteres, também é importante entender o funcionamento "por baixo do capô" e poder fazer sem ele ou replicá-lo, se necessário. Bom show.
Cancelado
1
Se você não deseja que sua classe seja carregada na memória, token_get_all é uma alternativa fantástica. É MUITO mais rápido que o Reflection e não sobrecarrega a memória do processo, se você precisar fazer isso com muitas classes.
Harold
+1 para a solução baseada em token! Compreender a análise baseada em token é um prazer, considerando o desempenho ... e, como sempre, há uma ótima pessoa que mostra como analisar constantes via token_get_all (). Muito obrigado!
Mwatzer # 1/16
Presumivelmente, isso atua apenas no arquivo único e não herda nenhuma constante das classes pai. De fato, essa técnica nem se importa com a classe - ela fornecerá todas as constantes no arquivo, mesmo no escopo global. É uma ótima ferramenta para explorar.
Jason em
14

No PHP5, você pode usar o Reflection: (referência manual)

$class = new ReflectionClass('Profile');
$consts = $class->getConstants();
Fase de análise
fonte
13

Pelos comentários dos documentos do PHP, se você pode usar o ReflectionClass (PHP 5):

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

A fonte está aqui.

mway
fonte
9

Usando ReflectionClass e getConstants()fornece exatamente o que você deseja:

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

Resultado:

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

Traço com método estático - para o resgate

Parece que é um bom lugar para usar Traits com uma função estática para estender a funcionalidade da classe. As características também nos permitem implementar essa funcionalidade em qualquer outra classe sem reescrever o mesmo código repetidamente (fique seco).

Use nossa característica 'ConstantExport' personalizada na classe Profile. Faça isso para todas as turmas que você precisar dessa funcionalidade.

/**
 * 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;

}

EXEMPLO DE USO

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

print_r($constList); // TEST

SAÍDAS:

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

Sim, você usa reflexão . Veja a saída de

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

Isso deve lhe dar a idéia do que você estará vendo.

caos
fonte
4

É útil ter um método dentro da classe para retornar suas próprias constantes.
Você pode fazer desta maneira:

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
fonte
3

Por que não colocá-los em uma variável de classe como uma matriz para começar? Facilita o loop.

private $_data = array("production"=>0 ...);
Detectar
fonte
2
Porque matrizes não são constantes? Se você implementar algo que deveria ser uma constante como variável, corre o risco de ser alterado ou desfeito inadvertidamente. Em outras palavras, você não pode depender deles permanecendo constantes.
precisa saber é o seguinte
3

Eventualmente com 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());
revogar
fonte
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_());
Юрий Светлов
fonte