Bagaimana cara saya mendapatkan nama kelas objek yang tidak memenuhi syarat (pendek)?

153

Bagaimana cara memeriksa kelas objek dalam lingkungan spasi nama PHP tanpa menentukan kelas namespace penuh.

Sebagai contoh misalkan saya memiliki perpustakaan objek / Entitas / Kontrak / Nama.

Kode berikut tidak berfungsi karena get_class mengembalikan kelas namespace penuh.

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

Kata kunci ajaib namespace mengembalikan namespace saat ini, yang tidak digunakan jika objek yang diuji memiliki namespace lain.

Saya hanya dapat menentukan classname lengkap dengan namespaces, tetapi ini tampaknya mengunci struktur kode. Juga tidak banyak digunakan jika saya ingin mengubah namespace secara dinamis.

Adakah yang bisa memikirkan cara yang efisien untuk melakukan ini. Saya kira satu opsi adalah regex.

Greg. Menambah
sumber
Tampaknya hampir sia-sia karena ruang nama yang berbeda dapat memiliki nama kelas yang sama didefinisikan di dalamnya, jadi bagaimana Anda akan mengatasinya? Dan itu karena nama kelas yang memenuhi syarat dikembalikan dalam sampel Anda
Alma Do
Saya menggunakan perangkat seluler, jadi saya tidak dapat mengirimkan jawaban yang layak, tetapi solusinya adalah refleksi, khususnya ReflectionClass :: getShortName - php.net/manual/en/reflectionclass.getshortname.php
lonesomeday
Bagi orang yang mencari alasan untuk menginginkan ini: ini mungkin berguna dalam fungsi helper di kelas dasar umum (yaitu beberapa ruang nama tidak pernah menjadi masalah dalam situasi ini).
Darren Cook

Jawaban:

182

Anda dapat melakukan ini dengan refleksi. Khususnya, Anda bisa menggunakan ReflectionClass::getShortNamemetode ini, yang mendapatkan nama kelas tanpa namespace-nya.

Pertama, Anda perlu membuat ReflectionClassinstance, dan kemudian memanggil getShortNamemetode instance itu:

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

Namun, saya tidak dapat membayangkan banyak keadaan di mana ini diinginkan. Jika Anda ingin agar objek tersebut adalah anggota kelas tertentu, cara mengujinya adalah dengan instanceof. Jika Anda ingin cara yang lebih fleksibel untuk memberi sinyal kendala tertentu, cara untuk melakukannya adalah dengan menulis antarmuka dan mengharuskan kode mengimplementasikan antarmuka itu. Sekali lagi, cara yang benar untuk melakukan ini adalah dengan instanceof. (Anda dapat melakukannya dengan ReflectionClass, tetapi kinerjanya akan jauh lebih buruk.)

lonesomeday
sumber
1
@ Greg.Forbes Karena Tenanttidak ada di namespace saat ini. Coba var_dump($tenant instanceof \Library\Entity\People\Tenant)saja. Juga, selidiki bagaimana menggunakan useoperator, dan konsep umum di balik ruang nama PHP!
lonesomeday
3
Saya harus menambahkan garis miring di depan seperti ini$reflect = new \ReflectionClass($object);
pemrogram
7
Saya biasanya tidak suka melakukan banyak voodoo ReflectionClass di aplikasi saya karena itu dapat menyebabkan hasil yang tidak terduga jika salah digunakan (metode yang dilindungi menjadi publik, dll). Anda dapat menggunakan string pengganti konstanta ajaib PHP sebagai gantinya: str_replace(__NAMESPACE__ . '\\', '', __CLASS__);. Ini juga jauh lebih cepat, dari segi kinerja.
Franklin P Strube
2
@ FrankrankPStrube Kecuali saya kehilangan sesuatu, yang mendapat nama pendek dari kelas saat ini, bukan kelas objek. Saya setuju bahwa penggunaan refleksi biasanya berarti Anda Melakukannya dengan Salah.
lonesomeday
1
Banyak orang menggunakan Refleksi untuk mengabaikan visibilitas anggota, yang BURUK. Jangan lakukan itu! Tetapi menyatakan bahwa penggunaan Refleksi secara umum adalah Voodoo dan Doing It Wrong memberi kesan yang salah pada orang. Anda tidak boleh menghindarinya, Anda harus memahaminya dan tahu kapan itu bermanfaat dan pada tingkat abstraksi apa.
Vanja D.
131

(new \ReflectionClass($obj))->getShortName(); adalah solusi terbaik berkaitan dengan kinerja.

Saya ingin tahu yang mana dari solusi yang disediakan adalah yang tercepat, jadi saya telah mengumpulkan sedikit tes.

Hasil

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

Kode

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

Hasilnya benar-benar mengejutkan saya. Saya pikir solusi meledak akan menjadi cara tercepat untuk pergi ...

Hirnhamster
sumber
1
Jawaban yang bagus Saya menjalankan kode yang sama tetapi saya mendapatkan hasil yang berbeda (Macbook Pro i7, ram 16 GB). Refleksi: 0,382, Basename: 0,380, Meledak: 0,399. Saya pikir itu tergantung pada sistem Anda apa yang terbaik ...
Tobias Nyholm
4
Jalankan PHP 10.000 kali dengan kode itu dan Anda mendapatkan hasil yang lebih baik. Di atas mungkin mengambil refleksi dari beberapa kumpulan, tetapi ini bukan perilaku yang biasa dari aplikasi di luar sana. Mereka hanya membutuhkannya sekali atau dua kali.
LeMike
6
Saya bertanya-tanya apakah tes ini berlaku ketika instantiating ReflectionClass pada objek yang lebih substansial daripada objek kecil Kelas A dalam pengujian Anda ...
Joe Green
2
menjalankan hanya satu iterasi bukannya 100000 memberikan hasil yang jauh berbeda: Refleksi: 1.0967254638672 100000 / s ClassA Basename: 0,81062316894531 100000th s ClassA Meledak: 0,50067901611328 100000th / s ClassA
mcmurphy
1
meledak ('\\', static :: class) [0]? bukankah itu mengembalikan bagian pertama namespace? harus mengembalikan bagian terakhir, bukan yang pertama
2oppin
86

Saya menambahkan substr ke pengujian https://stackoverflow.com/a/25472778/2386943 dan itulah cara fastet yang saya bisa uji (CentOS PHP 5.3.3, Ubuntu PHP 5.5.9) keduanya dengan i5.

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

Hasil

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

Kode

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

== UPDATE ==

Seperti disebutkan dalam komentar oleh @MrBandersnatch bahkan ada cara yang lebih cepat untuk melakukan ini:

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

Berikut adalah hasil tes yang diperbarui dengan "SubstringStrChr" (menyimpan hingga sekitar 0,001 detik):

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
MaBi
sumber
5
Hanya karena kami mendaftar untuk efisiensi, saya menemukan ini sebagai yang tercepat, perbandingan dari tes yang disediakan dalam solusi ini (strrchr (get_class ($ obj), '\\'), 1); Refleksi: 0,084223914146423 s ClassA - Basename: 0.13206427097321 s ClassA - Explode: 0.15331919193268 s ClassA - Substring: 0.068068099021912 s ClassA - Strrchar: 0.06472008228302 s ClassA -
ctatro85
Saya baru saja menemukan utas ini dan menambahkan patokan tambahan untuk diuji str_replace(__NAMESPACE__ . '\\', '', __CLASS__);. Hasil pada mesin virtual yang lemah menunjukkan hampir dua kali lebih cepat dari semua ini. 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 Anda benar. Saya menguji solusi Anda dan itu menyelamatkan saya sekitar 0,001 detik. Saya memperbarui jawaban saya dengan Anda!
MaBi
3
Peringatan: kode ini tidak berfungsi dengan kelas-kelas di namespace global (yaitu: nama lengkap mereka sama dengan nama pendek mereka)! Saran saya untuk menguji sesuatu seperti: if ($pos = strrchr(static::class, '\\')) { .. } else { ... }.
Tristan Jahier
1
Untuk membuatnya bekerja di namespace global juga, cukup tambahkan nama class dengan backslash :) - yaitu:$classNameShort = substr(strrchr('\\' . get_class($this), '\\'), 1);
rosell.dk
25

Ini adalah cara yang lebih mudah untuk melakukan ini jika Anda menggunakan kerangka PHP Laravel:

<?php

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

// usage inside a class
// returns HelloWorld
$name = class_basename(__CLASS__);
spetsnaz
sumber
8
Ini bukan fungsi php bawaan, sepertinya fungsi pembantu yang disediakan oleh laravel.
Steve Buzonas
6
Saya pikir dia mengatakan itu
Scott
4
Terima kasih, saya menggunakan Laravel dan jawaban ini menghemat banyak waktu.
Jeremy Wadhams
18

Saya menggunakan ini:

basename(str_replace('\\', '/', get_class($object)));
arzzzen
sumber
Anda juga dapat mencoba: $ className = meledak ('\\', basename (get_class ($ this))); $ className = array_pop ($ className); untuk mendapatkan nama kelas yang sederhana. Atau gunakan substr.
dompie
13
Hanya bekerja pada Windows Di Windows, baik slash (/) dan backslash () digunakan sebagai karakter pemisah direktori. Di lingkungan lain, ini adalah garis miring (/) php.net/manual/en/function.basename.php
OzzyCzech
Saya sudah memperbaikinya sekarang. Terima kasih, @OzzyCzech.
Theodore R. Smith
1
@OzzyCzech Saya baru saja mengalami hal ini saat pindah dari Windows ke Ubuntu .... menjengkelkan. Lanjutkan menggunakan solusi yang disebutkan dalam pembaruan MaBi.
Chris Baker
@OzzyCzech Kenapa hanya bekerja di Windows? pertanyaannya adalah tentang nama namespace yang sepenuhnya memenuhi syarat jika saya tidak salah juga tahun yang lalu, dan namespace tidak spesifik OS, dan selalu dengan backslash seperti pemisah direktori windows.
FantomX1
16

Untuk mendapatkan nama pendek sebagai satu-liner (sejak PHP 5.4 ):

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

Ini adalah pendekatan yang bersih dan cepat masuk akal .

flori
sumber
1
Saya ingin tahu bagaimana ini membandingkan dengan ekstraksi string dalam tolok ukur. Sepertinya ini akan jauh lebih lambat.
Kontak Tidak
12

Saya menemukan diri saya dalam situasi yang unik di mana instanceoftidak dapat digunakan (khusus sifat-sifat namespace) dan saya membutuhkan nama pendek dengan cara yang paling efisien mungkin jadi saya telah melakukan tolok ukur sendiri. Ini mencakup semua metode & variasi yang berbeda dari jawaban dalam pertanyaan ini.

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

Daftar seluruh hasil ada di sini tetapi di sini adalah yang utama:

  • Jika Anda akan menggunakan refleksi lagian, menggunakan $obj->getShortName()adalah metode tercepat namun ; menggunakan refleksi hanya untuk mendapatkan nama pendek itu adalah metode yang paling lambat.
  • 'strrpos'dapat mengembalikan nilai yang salah jika objek tidak ada dalam namespace jadi sementara 'safe strrpos'sedikit lebih lambat saya akan mengatakan ini adalah pemenangnya.
  • Untuk membuat 'basename'kompatibel antara Linux dan Windows Anda harus menggunakan str_replace()yang membuat metode ini paling lambat dari semuanya.

Tabel hasil yang disederhanakan, kecepatan diukur dibandingkan dengan metode paling lambat:

+-----------------+--------+
| 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%  |
+-----------------+--------+
Xorifelse
sumber
8

Anda bisa menggunakan explodeuntuk memisahkan namespace dan enduntuk mendapatkan nama kelas:

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

Yii jalan

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

Yii menggunakan metode ini dalam generator kode Gii-nya

Dokumentasi metode

Metode ini mirip dengan nama fungsi php () kecuali bahwa ia akan memperlakukan kedua \ dan / sebagai pemisah direktori, terlepas dari sistem operasi. Metode ini terutama dibuat untuk bekerja di ruang nama php. Ketika bekerja dengan jalur file nyata, nama samaran php () seharusnya berfungsi dengan baik untuk Anda. Catatan: metode ini tidak mengetahui sistem file yang sebenarnya, atau komponen jalur seperti "..".

Informasi lebih lanjut:

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

mariovials
sumber
Selamat datang di Stack Overflow. Harap berikan informasi lebih lanjut untuk jawaban Anda. Apa yang dilakukan dan bagaimana cara menggunakannya.
Jens
1
Ini bekerja untuk saya di Windows tetapi tidak di Linux, mungkin karena ruang nama dalam bentuk backslash direktori Windows '\', sedangkan nama dasar linux menganggap pemisah direktori forward slash '/'. Jadi saya mengatasinya dengan strtr. ' basename (strtr ($ class, '\\', '/'))
FantomX1
6

Ini adalah solusi sederhana untuk 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()));
        }
    }
}

Apa yang akan kembali?

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
}

Nama kelas yang diperluas dan namespace berfungsi dengan baik untuk:

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
}

Bagaimana dengan kelas di namespace global?

namespace {

    class ClassWithoutNamespace {
        use \Names;
    }

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

Jika Anda perlu tahu nama kelas yang dipanggil dari dalam kelas, dan tidak ingin namespace, Anda bisa menggunakan yang ini

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

Ini bagus ketika Anda memiliki metode di dalam kelas yang diperluas oleh kelas lain. Selain itu, ini juga berfungsi jika ruang nama tidak digunakan sama sekali.

Contoh:

<?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)
Nino Škopac
sumber
2

Berdasarkan jawaban @MaBi, saya membuat ini:

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

Yang dapat Anda gunakan seperti itu:

namespace Foo\Bar\Baz;

class A
{
    use ClassShortNameTrait;
}

A::classkembali Foo\Bar\Baz\A, tetapi A::getClassShortName()kembali A.

Bekerja untuk PHP> = 5.5.

Tristan Jahier
sumber
2

Saya tahu ini adalah posting lama tapi ini yang saya gunakan - Lebih cepat dari semua yang diposting di atas panggil metode ini dari kelas Anda, jauh lebih cepat daripada menggunakan Refleksi

namespace Foo\Bar\Baz;

class Test {
    public function getClass() {
        return str_replace(__NAMESPACE__.'\\', '', static::class);
    }
}
Seth
sumber
Sayangnya itu hanya berfungsi jika Anda memanggilnya di kelas yang namanya Anda inginkan, bukan pada sembarang nama kelas sebagai string.
jurchiks
1

Ditemukan di halaman dokumentasi get_class , di mana itu diposting oleh saya di 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];
}

Tetapi ide ruang nama adalah untuk menyusun kode Anda. Itu juga berarti bahwa Anda dapat memiliki kelas dengan nama yang sama di beberapa ruang nama. Jadi secara teoritis, objek yang Anda lewati dapat memiliki nama (dilucuti) nama kelas, sementara masih menjadi objek yang sama sekali berbeda dari yang Anda harapkan.

Selain itu, Anda mungkin ingin memeriksa kelas dasar tertentu , dalam hal get_classini tidak melakukan trik sama sekali. Anda mungkin ingin memeriksa operator instanceof.

GolezTrol
sumber
1

Anda mungkin mendapatkan hasil yang tidak terduga ketika kelas tidak memiliki namespace. Yaitu get_classkembali Foo, maka $baseClassakan menjadi oo.

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

Ini dapat dengan mudah diperbaiki dengan awalan get_classdengan garis miring terbalik:

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

Sekarang juga kelas tanpa namespace akan mengembalikan nilai yang tepat.

Tim
sumber
1

Regex lama yang baik tampaknya lebih cepat daripada sebagian besar metode yang ditunjukkan sebelumnya:

// both of the below calls will output: ShortClassName

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

Jadi ini berfungsi bahkan ketika Anda memberikan nama kelas pendek atau nama kelas yang memenuhi syarat (kanonik).

Apa yang dilakukan regex adalah ia mengonsumsi semua karakter sebelumnya hingga separator terakhir ditemukan (yang juga dikonsumsi). Jadi string yang tersisa akan menjadi nama kelas pendek.

Jika Anda ingin menggunakan pemisah yang berbeda (mis. /) Maka gunakan saja pemisah itu. Ingatlah untuk menghindari backslash (mis. \) Dan juga char pattern (mis. /) Dalam pola input.

Eugen Mihailescu
sumber
1

Karena "ReflectionClass" dapat bergantung pada versi, gunakan saja yang berikut:

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

atau bahkan jelas

if(class_basename(ClassName::class) == 'ClassName') {
... do this ...
}
Martin Tonev
sumber
0

Mengutip php.net:

Pada Windows, baik slash (/) dan backslash () digunakan sebagai karakter pemisah direktori. Di lingkungan lain, ini adalah garis miring (/).

Berdasarkan info ini dan memperluas dari jawaban arzzzen ini harus bekerja pada sistem Windows dan Nix *:

<?php

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

Catatan: Saya melakukan tolok ukur ReflectionClassterhadap basename+str_replace+get_classdan menggunakan refleksi sekitar 20% lebih cepat daripada menggunakan pendekatan basename, tapi YMMV.

berisik
sumber
0

Solusi termudah dan tercepat yang bekerja di lingkungan apa pun adalah:

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

?>
Fleshgrinder
sumber
1
Inilah sebabnya saya berharap PHP memiliki operator informasi kelas internal. Instantiating reflektor eksternal untuk melakukan apa yang seharusnya sesederhana $Object->__class->getShortName()benar - benar membuatku kesal tentang PHP. Pendekatan Anda berhasil, tetapi sekarang Anda menempatkan metode konkret di kelas Anda hanya untuk mengekspos apa yang seharusnya menjadi konstruksi bahasa.
AgmLauncher
PHP tanpa fungsi "konkret" (atau harus kita sebut prosedural) tidak mungkin. Mari kita tunggu PHP 6 (yah, jika itu pernah datang).
Fleshgrinder
0
$shortClassName = join('',array_slice(explode('\\', $longClassName), -1));
jahat
sumber
0

Jika Anda hanya menghapus ruang nama dan menginginkan apa pun setelah \ terakhir dalam nama kelas dengan namespace (atau hanya nama jika tidak ada '\') Anda dapat melakukan sesuatu seperti ini:

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

Pada dasarnya ini regex untuk mendapatkan kombinasi karakter atau garis miring terbalik dan hingga garis miring terbalik terakhir yang hanya mengembalikan karakter garis miring terbalik dan sampai akhir string. Menambahkan? setelah pengelompokan pertama berarti jika kecocokan pola tidak ada, itu hanya mengembalikan string penuh.

Scott
sumber
0

Tercepat yang saya temukan di sini untuk PHP 7.2diUbubntu 18.04

preg_replace('/^(\w+\\\)*/', '', static::class)
Vasilii Suricov
sumber