Como verifico a classe de um objeto no ambiente espaçado de nomes PHP sem especificar a classe espaçada de nomes completa.
Por exemplo, suponha que eu tenha uma biblioteca de objetos / Entidade / Contrato / Nome.
O código a seguir não funciona, pois get_class retorna a classe cheia de namespace.
If(get_class($object) == 'Name') {
... do this ...
}
A palavra-chave mágica do espaço para nome retorna o espaço para nome atual, que não será útil se o objeto testado tiver outro espaço para nome.
Eu poderia simplesmente especificar o nome completo da classe com espaços para nome, mas isso parece bloquear a estrutura do código. Também não é muito útil se eu quiser alterar o espaço para nome dinamicamente.
Alguém pode pensar em uma maneira eficiente de fazer isso. Eu acho que uma opção é regex.
php
class
namespaces
Greg.Forbes
fonte
fonte
Respostas:
Você pode fazer isso com reflexão. Especificamente, você pode usar o
ReflectionClass::getShortName
método, que obtém o nome da classe sem seu espaço para nome.Primeiro, você precisa criar uma
ReflectionClass
instância e, em seguida, chame ogetShortName
método dessa instância:No entanto, não consigo imaginar muitas circunstâncias em que isso seria desejável. Se você deseja exigir que o objeto seja membro de uma determinada classe, é a maneira de testá-lo
instanceof
. Se você deseja uma maneira mais flexível de sinalizar certas restrições, a maneira de fazer isso é escrever uma interface e exigir que o código implemente essa interface. Novamente, a maneira correta de fazer isso é cominstanceof
. (Você pode fazer isso comReflectionClass
, mas teria um desempenho muito pior.)fonte
Tenant
não existe no espaço para nome atual. Tente emvar_dump($tenant instanceof \Library\Entity\People\Tenant)
vez disso. Além disso, investigue como usar ouse
operador e o conceito geral por trás dos espaços para nome PHP!$reflect = new \ReflectionClass($object);
str_replace(__NAMESPACE__ . '\\', '', __CLASS__);
. Também é muito mais rápido, em termos de desempenho.(new \ReflectionClass($obj))->getShortName();
é a melhor solução em relação ao desempenho.Fiquei curioso para saber qual das soluções fornecidas é a mais rápida, por isso reuni um pequeno teste.
Resultados
Código
Os resultados realmente me surpreenderam. Eu pensei que a solução de explosão seria o caminho mais rápido a seguir ...
fonte
Adicionei substr ao teste de https://stackoverflow.com/a/25472778/2386943 e essa é a maneira mais rápida de testar (CentOS PHP 5.3.3, Ubuntu PHP 5.5.9), ambos com um i5.
Resultados
Código
== ATUALIZAÇÃO ==
Como mencionado nos comentários de @MrBandersnatch, existe ainda uma maneira mais rápida de fazer isso:
Aqui estão os resultados atualizados dos testes com "SubstringStrChr" (economiza até 0,001 s):
fonte
str_replace(__NAMESPACE__ . '\\', '', __CLASS__);
. Os resultados em uma máquina virtual fraca mostraram que ela era quase duas vezes mais rápida que todas elas.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
if ($pos = strrchr(static::class, '\\')) { .. } else { ... }
.$classNameShort = substr(strrchr('\\' . get_class($this), '\\'), 1);
Aqui está uma maneira mais fácil de fazer isso se você estiver usando a estrutura PHP do Laravel:
fonte
Eu uso isso:
fonte
Para obter o nome abreviado como uma linha (desde o PHP 5.4 ):
É uma abordagem limpa e razoavelmente rápida .
fonte
Eu me encontrei em uma situação única em
instanceof
que não podia ser usado (traços específicos no espaço de nome) e precisava do nome abreviado da maneira mais eficiente possível, para que eu próprio fiz uma pequena referência. Inclui todos os diferentes métodos e variações das respostas nesta pergunta.Uma lista de todo o resultado está aqui, mas aqui estão os destaques:
$obj->getShortName()
é o método mais rápido no entanto ; usando apenas reflexão para obter o nome abreviado, é quase o método mais lento.'strrpos'
pode retornar um valor errado se o objeto não estiver em um espaço para nome;'safe strrpos'
estiver um pouco mais lento, eu diria que esse é o vencedor.'basename'
compatível entre Linux e Windows, você precisa usar ostr_replace()
que torna esse método o mais lento de todos.Uma tabela simplificada de resultados, a velocidade é medida em comparação com o método mais lento:
fonte
Você pode usar
explode
para separar o espaçoend
para nome e obter o nome da classe:fonte
Yii way
O Yii usa esse método em seu gerador de código Gii
Documentação do método
Mais Informações:
https://github.com/yiisoft/yii2/blob/master/framework/helpers/BaseStringHelper.php http://www.yiiframework.com/doc-2.0/yii-helpers-basestringhelper.html#basename()-detalhe
fonte
Aqui está uma solução simples para PHP 5.4+
Qual será o retorno?
O nome da classe e o espaço de nomes estendidos funcionam bem para:
E a classe no namespace global?
fonte
Se você precisar saber o nome da classe que foi chamado de dentro de uma classe e não desejar o espaço para nome, use este
Isso é ótimo quando você tem um método dentro de uma classe que é estendido por outras classes. Além disso, isso também funciona se os namespaces não forem usados.
Exemplo:
fonte
Com base na resposta de @MaBi, fiz o seguinte:
Que você pode usar assim:
A::class
retornaFoo\Bar\Baz\A
, masA::getClassShortName()
retornaA
.Funciona para PHP> = 5.5.
fonte
Eu sei que este é um post antigo, mas é isso que eu uso - mais rápido do que o post acima, basta chamar esse método da sua classe, muito mais rápido do que usar o Reflection
fonte
Encontrado na página de documentação de get_class , onde foi postada por mim no nwhiting dot com .
Mas a idéia de espaços para nome é estruturar seu código. Isso também significa que você pode ter classes com o mesmo nome em vários espaços para nome. Então, teoricamente, o objeto que você passa pode ter o nome da classe (despojado), enquanto continua sendo um objeto totalmente diferente do que você espera.
Além disso, convém verificar uma classe base específica , caso em
get_class
que não faz o truque. Você pode querer verificar o operadorinstanceof
.fonte
Você pode obter um resultado inesperado quando a classe não possui um espaço para nome. Ou seja ,
get_class
retornaFoo
, então$baseClass
seriaoo
.Isso pode ser facilmente corrigido prefixando
get_class
uma barra invertida:Agora também as classes sem um espaço para nome retornarão o valor correto.
fonte
Um bom e velho regex parece ser mais rápido que a maioria dos métodos mostrados anteriormente:
Portanto, isso funciona mesmo quando você fornece um nome de classe curto ou um nome de classe totalmente qualificado (canônico).
O que a regex faz é que consome todos os caracteres anteriores até que o último separador seja encontrado (que também é consumido). Portanto, a sequência restante será o nome curto da classe.
Se você deseja usar um separador diferente (por exemplo, /), basta usar esse separador. Lembre-se de escapar da barra invertida (ex. \) E também do padrão char (ex. /) No padrão de entrada.
fonte
Como "ReflectionClass" pode ser uma versão dependente, basta usar o seguinte:
ou até claro
fonte
Citando php.net:
Com base nessas informações e na expansão da resposta da arzzzen, isso deve funcionar nos sistemas Windows e Nix *:
Nota: Fiz um benchmark
ReflectionClass
contrabasename+str_replace+get_class
e o uso da reflexão é aproximadamente 20% mais rápido que o uso da abordagem de nome de base, mas o YMMV.fonte
A solução mais rápida e fácil que funciona em qualquer ambiente é:
fonte
$Object->__class->getShortName()
realmente me irrita com o PHP. Sua abordagem funciona, mas agora você está colocando métodos concretos em suas aulas apenas para expor o que deve ser uma construção de linguagem.fonte
Se você está apenas removendo os espaços para nome e quiser algo após o último \ em um nome de classe com espaço para nome (ou apenas o nome se não houver '\'), poderá fazer algo assim:
Basicamente, é regex obter qualquer combinação de caracteres ou barras invertidas e, até a última barra invertida, retornar apenas os caracteres que não são invertidos e até o final da string. Adicionando o? depois que o primeiro agrupamento significa que, se a correspondência de padrões não existir, ela retornará a sequência completa.
fonte
Mais rápido que eu encontrei aqui para
PHP 7.2
onUbubntu 18.04
fonte