Làm thế nào để tôi có được tên lớp không đủ tiêu chuẩn (ngắn) của một đối tượng?


153

Làm cách nào để kiểm tra lớp của một đối tượng trong môi trường khoảng cách tên PHP mà không chỉ định lớp có tên đầy đủ.

Ví dụ: giả sử tôi có một thư viện đối tượng / Thực thể / Hợp đồng / Tên.

Đoạn mã sau không hoạt động vì get_group trả về lớp được đặt tên đầy đủ.

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

Từ khóa ma thuật không gian tên trả về không gian tên hiện tại, không sử dụng nếu đối tượng được kiểm tra có không gian tên khác.

Tôi chỉ có thể chỉ định tên lớp đầy đủ với các không gian tên, nhưng điều này dường như khóa trong cấu trúc của mã. Cũng không sử dụng nhiều nếu tôi muốn thay đổi không gian tên động.

Bất cứ ai cũng có thể nghĩ ra một cách hiệu quả để làm điều này. Tôi đoán một lựa chọn là regex.


Có vẻ như gần như vô nghĩa vì các không gian tên khác nhau có thể có cùng tên lớp được định nghĩa bên trong chúng, vậy bạn sẽ xử lý như thế nào? Và đó là vì tên lớp đủ điều kiện được trả về trong mẫu của bạn
Alma Do

Tôi đang trên một thiết bị di động, vì vậy tôi không thể gửi trả lời đàng hoàng, nhưng giải pháp này là phản xạ, đặc biệt ReflectionClass :: getShortName - php.net/manual/en/reflectionclass.getshortname.php
lonesomeday

Đối với những người tìm kiếm một lý do để muốn điều này: nó có thể hữu ích trong một hàm trợ giúp trong một lớp cơ sở chung (nghĩa là nhiều không gian tên không bao giờ là một vấn đề trong tình huống này).
Darren Cook

Câu trả lời:


182

Bạn có thể làm điều này với sự phản ánh. Cụ thể, bạn có thể sử dụng ReflectionClass::getShortNamephương thức, lấy tên của lớp mà không có không gian tên của nó.

Trước tiên, bạn cần xây dựng một ReflectionClassthể hiện, và sau đó gọi getShortNamephương thức của thể hiện đó:

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

Tuy nhiên, tôi không thể tưởng tượng nhiều trường hợp điều này sẽ được mong muốn. Nếu bạn muốn yêu cầu đối tượng là thành viên của một lớp nhất định, cách để kiểm tra nó là với instanceof. Nếu bạn muốn một cách linh hoạt hơn để báo hiệu một số ràng buộc nhất định, cách để làm điều đó là viết một giao diện và yêu cầu mã thực hiện giao diện đó. Một lần nữa, cách chính xác để làm điều này là với instanceof. (Bạn có thể làm điều đó với ReflectionClass, nhưng nó sẽ có hiệu suất kém hơn nhiều.)


1
@ Greg.Forbes Vì Tenantkhông tồn tại trong không gian tên hiện tại. Hãy thử var_dump($tenant instanceof \Library\Entity\People\Tenant)thay thế. Ngoài ra, điều tra cách sử dụng usetoán tử và khái niệm chung đằng sau các không gian tên PHP!
cô đơn

3
Tôi đã phải thêm một dấu gạch chéo ở phía trước như thế này$reflect = new \ReflectionClass($object);
prograhammer

7
Nói chung, tôi không muốn thực hiện nhiều voodoo ReflectionClass trong ứng dụng của mình vì nó có thể dẫn đến kết quả không mong muốn nếu sử dụng sai (phương pháp được bảo vệ trở nên công khai, v.v.). Thay vào đó, bạn có thể sử dụng thay thế chuỗi đơn giản trên các hằng số ma thuật PHP : str_replace(__NAMESPACE__ . '\\', '', __CLASS__);. Nó cũng nhanh hơn nhiều, hiệu suất khôn ngoan.
Franklin P Strube

2
@FranklinPStrube Trừ khi tôi thiếu một cái gì đó, đó là tên viết tắt của lớp hiện tại, thay vì lớp của đối tượng. Tôi đồng ý rằng việc sử dụng sự phản chiếu thường có nghĩa là bạn đang làm sai.
lonesomeday

1
Nhiều người sử dụng Reflection để ghi đè khả năng hiển thị của thành viên, đó là BAD. Đừng làm thế! Nhưng nói rằng việc sử dụng Refl Refl nói chung là Voodoo và Making It Wrong mang lại cho mọi người ấn tượng sai. Bạn không nên tránh chúng, bạn nên hiểu chúng và biết khi nào chúng có lợi và mức độ trừu tượng.
Vanja D.

131

(new \ReflectionClass($obj))->getShortName(); là giải pháp tốt nhất liên quan đến hiệu suất.

Tôi tò mò xem giải pháp nào được cung cấp là nhanh nhất, vì vậy tôi đã thử nghiệm một chút.

Các kết quả

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

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

Kết quả thực sự làm tôi ngạc nhiên. Tôi nghĩ giải pháp phát nổ sẽ là cách nhanh nhất để đi ...


1
Câu trả lời chính xác. Tôi đã chạy cùng một mã nhưng tôi đã nhận được một kết quả khác (Macbook Pro i7, ram 16 GB). Phản xạ: 0.382, Tên cơ sở: 0.380, Phát nổ: 0.399. Tôi nghĩ rằng nó phụ thuộc vào hệ thống của bạn những gì là tốt nhất ...
Tobias Nyholm

4
Chạy PHP 10 000 lần với mã đó và bạn sẽ có kết quả tốt hơn. Ở trên có thể lấy phản ánh từ một số nhóm, nhưng đây không phải là hành vi thông thường của các ứng dụng ngoài kia. Họ chỉ cần một hoặc hai lần.
LeMike

6
Tôi tự hỏi liệu bài kiểm tra này có đúng không khi khởi tạo ReflectionClass trên một vật thể quan trọng hơn vật thể nhỏ của Lớp A trong bài kiểm tra của bạn ...
Joe Green

2
chạy chỉ là một lần lặp thay vì 100000 đưa ra một kết quả khác nhau nhiều: Reflection: 1,0967254638672 100000 / s ClassA basename: ,81062316894531 100000 / s ClassA Explode: ,50067901611328 100000 / s ClassA
McMurphy

1
phát nổ ('\\', static :: class) [0]? nó không trả về phần đầu tiên của không gian tên sao? nên trả lại phần cuối cùng, không phải phần đầu tiên
2oppin

86

Tôi đã thêm chất nền vào kiểm tra https://stackoverflow.com/a/25472778/2386943 và đó là cách nhanh nhất mà tôi có thể kiểm tra (CentOS PHP 5.3.3, Ubuntu PHP 5.5.9) cả với i5.

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

Các kết quả

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

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

== CẬP NHẬT ==

Như đã đề cập trong các bình luận của @MrBandersnatch, thậm chí còn có một cách nhanh hơn để làm điều này:

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

Dưới đây là kết quả kiểm tra được cập nhật với "SubopesStrChr" (tiết kiệm tới khoảng 0,001 giây):

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
Chỉ vì chúng tôi liệt kê tính hiệu quả, tôi thấy đây là cách nhanh nhất, so sánh từ thử nghiệm được cung cấp trong chất nền giải pháp này (strrchr (get_group ($ obj), '\\'), 1); Reflection: ,084223914146423 s ClassA - basename: ,13206427097321 s ClassA - Explode: ,15331919193268 s ClassA - substring: ,068068099021912 s ClassA - Strrchar: ,06472008228302 s ClassA -
ctatro85

Tôi chỉ đi qua chủ đề này và thêm một điểm chuẩn để kiểm tra str_replace(__NAMESPACE__ . '\\', '', __CLASS__);. Kết quả trên một máy ảo yếu cho thấy nó nhanh gần gấp đôi so với tất cả những thứ này. 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 bạn đúng. Tôi đã thử nghiệm giải pháp của bạn và nó đã tiết kiệm cho tôi khoảng 0,001 giây. Tôi đã cập nhật câu trả lời của tôi với bạn!
MaBi

3
Cảnh báo: mã này không hoạt động với các lớp trong không gian tên toàn cầu (nghĩa là: tên đầy đủ của chúng bằng tên ngắn của chúng)! Tôi khuyên bạn nên thử nghiệm một cái gì đó như : if ($pos = strrchr(static::class, '\\')) { .. } else { ... }.
Tristan Jahier

1
Để làm cho nó hoạt động trong không gian tên toàn cầu, chỉ cần thêm tên lớp bằng dấu gạch chéo ngược :) - tức là:$classNameShort = substr(strrchr('\\' . get_class($this), '\\'), 1);
rosell.dk

25

Đây là một cách dễ dàng hơn để làm điều này nếu bạn đang sử dụng khung công tác PHP của Laravel:

<?php

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

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

8
Đây không phải là một hàm php dựng sẵn, nó trông giống như một hàm trợ giúp được cung cấp bởi laravel.
Steve Buzonas

6
Tôi nghĩ rằng anh ấy đã nói điều đó
Scott

4
Cảm ơn, tôi đang sử dụng Laravel và câu trả lời này đã tiết kiệm cho tôi rất nhiều thời gian.
Jeremy Wadhams


18

Tôi sử dụng cái này:

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

Bạn cũng có thể thử: $ className = explode ('\\', tên cơ sở (get_group ($ this))); $ className = mảng_pop ($ className); để có được tên lớp đơn giản. Hoặc sử dụng chất nền.
dompie

13
Chỉ hoạt động trên Windows Trên Windows, cả dấu gạch chéo (/) và dấu gạch chéo ngược () được sử dụng làm ký tự phân tách thư mục. Trong môi trường khác, nó là dấu gạch chéo (/) php.net/manual/en/function.basename.php
OzzyCzech

Tôi đã sửa nó bây giờ. Cảm ơn, @OzzyC817.
Theodore R. Smith

1
@OzzyC817 Tôi vừa gặp phải vấn đề này trong khi chuyển từ Windows sang Ubuntu .... thật điên rồ. Làm tổn thương bằng cách sử dụng giải pháp được đề cập trong bản cập nhật của MaBi's.
Chris Baker

@OzzyC817 Làm thế nào chỉ hoạt động trên Windows? câu hỏi liên quan đến tên không gian tên đủ điều kiện nếu tôi không sai cách đây nhiều năm và không gian tên không phải là hệ điều hành cụ thể và luôn có dấu gạch chéo ngược như dấu tách thư mục windows.
FantomX1

16

Để có được tên ngắn là một lớp lót (kể từ PHP 5.4 ):

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

Đó là một cách tiếp cận sạch sẽ và nhanh chóng hợp lý .


1
Tôi tự hỏi làm thế nào điều này so sánh với một trích xuất chuỗi trong điểm chuẩn. Có vẻ như điều này sẽ chậm hơn nhiều.
Liên hệ chưa được xác minh

12

Tôi thấy mình trong một tình huống duy nhất instanceofkhông thể sử dụng (đặc biệt là các đặc điểm được đặt tên) và tôi cần tên ngắn theo cách hiệu quả nhất có thể nên tôi đã tự mình thực hiện một số điểm chuẩn nhỏ. Nó bao gồm tất cả các phương pháp & biến thể khác nhau từ các câu trả lời trong câu hỏi này.

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

Một danh sách của toàn bộ kết quả có ở đây nhưng đây là những điểm nổi bật:

  • Tuy nhiên , nếu bạn định sử dụng phản xạ, thì sử dụng $obj->getShortName()là phương pháp nhanh nhất ; sử dụng phản chiếu chỉ để có được những tên viết tắt nó gần như là phương pháp chậm nhất.
  • 'strrpos'có thể trả về một giá trị sai nếu đối tượng không ở trong một không gian tên vì vậy trong khi 'safe strrpos'chậm hơn một chút tôi sẽ nói đây là người chiến thắng.
  • Để 'basename'tương thích giữa Linux và Windows, bạn cần sử dụng str_replace()phương pháp này làm cho phương thức này chậm nhất.

Một bảng kết quả được đơn giản hóa, tốc độ được đo so với phương pháp chậm nhất:

+-----------------+--------+
| 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

Bạn có thể sử dụng explodeđể phân tách không gian tên và endđể lấy tên lớp:

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

7

Cách của bạn

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

Yii sử dụng phương thức này trong trình tạo mã Gii của nó

Tài liệu phương pháp

Phương thức này tương tự như tên cơ sở của hàm php () ngoại trừ việc nó sẽ coi cả \ và / là các dấu tách thư mục, độc lập với hệ điều hành. Phương pháp này chủ yếu được tạo ra để làm việc trên các không gian tên php. Khi làm việc với các đường dẫn tệp thực, tên cơ sở của php () sẽ hoạt động tốt với bạn. Lưu ý: phương pháp này không nhận thức được hệ thống tập tin thực tế hoặc các thành phần đường dẫn như "..".

Thêm thông tin:

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


Chào mừng bạn đến với Stack Overflow. Vui lòng cung cấp thêm thông tin cho câu trả lời của bạn. Điều này làm gì và làm thế nào người ta có thể sử dụng nó.
Jens

1
Điều này làm việc cho tôi trên Windows nhưng không phải trên Linux, có thể do không gian tên ở dạng thư mục Windows bị gạch chéo '\', trong khi tên cơ sở linux xem xét dấu tách thư mục chuyển tiếp dấu gạch chéo '/'. Vì vậy, tôi đã làm việc xung quanh với strtr. ' tên cơ sở (strtr ($ class, '\\', '/'))
FantomX1

6

Đây là giải pháp đơn giản cho 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()));
        }
    }
}

Điều gì sẽ trở lại?

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
}

Tên lớp và không gian tên mở rộng hoạt động tốt để:

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
}

Còn lớp trong không gian tên toàn cầu thì sao?

namespace {

    class ClassWithoutNamespace {
        use \Names;
    }

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

3

Nếu bạn cần biết tên lớp được gọi từ bên trong một lớp và không muốn không gian tên, bạn có thể sử dụng tên này

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

Điều này thật tuyệt khi bạn có một phương thức bên trong một lớp được mở rộng bởi các lớp khác. Hơn nữa, điều này cũng hoạt động nếu không gian tên không được sử dụng.

Thí dụ:

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

Dựa trên câu trả lời của @MaBi, tôi đã thực hiện điều này:

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

Mà bạn có thể sử dụng như thế:

namespace Foo\Bar\Baz;

class A
{
    use ClassShortNameTrait;
}

A::classtrả lại Foo\Bar\Baz\A, nhưng A::getClassShortName()trả lạiA .

Hoạt động cho PHP> = 5.5.


2

Tôi biết đây là một bài viết cũ nhưng đây là những gì tôi sử dụng - Nhanh hơn tất cả những gì được đăng ở trên chỉ cần gọi phương thức này từ lớp của bạn, nhanh hơn rất nhiều so với sử dụng Reflection

namespace Foo\Bar\Baz;

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

Thật không may, nó chỉ hoạt động nếu bạn gọi nó trong lớp có tên bạn muốn, không phải trên bất kỳ tên lớp nào dưới dạng chuỗi.
Nhím

1

Tìm thấy trên trang tài liệu của get_group , nơi nó được đăng bởi tôi tại 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];
}

Nhưng ý tưởng về không gian tên là cấu trúc mã của bạn. Điều đó cũng có nghĩa là bạn có thể có các lớp có cùng tên trong nhiều không gian tên. Vì vậy, về mặt lý thuyết, đối tượng bạn vượt qua có thể có tên lớp (tước), trong khi vẫn là một đối tượng hoàn toàn khác so với bạn mong đợi.

Bên cạnh đó, bạn có thể muốn kiểm tra một lớp cơ sở cụ thể , trong trường hợp get_classđó không thực hiện thủ thuật nào cả. Bạn có thể muốn kiểm tra các nhà điều hành instanceof.


1

Bạn có thể nhận được một kết quả bất ngờ khi lớp không có không gian tên. Tức là get_classtrở về Foo, sau đó $baseClasssẽ được oo.

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

Điều này có thể dễ dàng được khắc phục bằng tiền tố get_classvới dấu gạch chéo ngược:

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

Bây giờ các lớp không có không gian tên sẽ trả về giá trị đúng.


1

Một regex cũ tốt dường như nhanh hơn hầu hết các phương thức được hiển thị trước đó:

// both of the below calls will output: ShortClassName

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

Vì vậy, điều này hoạt động ngay cả khi bạn cung cấp một tên lớp ngắn hoặc một tên lớp đủ điều kiện (chính tắc).

Những gì regex làm là nó tiêu thụ tất cả các ký tự trước đó cho đến khi phân tách cuối cùng được tìm thấy (cũng được tiêu thụ). Vì vậy, chuỗi còn lại sẽ là tên lớp ngắn.

Nếu bạn muốn sử dụng một dấu phân cách khác (ví dụ. /) Thì chỉ cần sử dụng dấu phân cách đó để thay thế. Nhớ thoát dấu gạch chéo ngược (nghĩa là. \) Và cả mẫu char (tức là. /) Trong mẫu đầu vào.


1

Bởi vì "ReflectionClass" có thể là phiên bản phụ thuộc, chỉ cần sử dụng như sau:

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

hoặc thậm chí rõ ràng

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

0

Trích dẫn php.net:

Trên Windows, cả dấu gạch chéo (/) và dấu gạch chéo ngược () được sử dụng làm ký tự phân tách thư mục. Trong các môi trường khác, đó là dấu gạch chéo (/).

Dựa trên thông tin này và mở rộng từ câu trả lời arzzzen, điều này sẽ hoạt động trên cả hệ thống Windows và Nix *:

<?php

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

Lưu ý: Tôi đã thực hiện một điểm chuẩn ReflectionClassso với basename+str_replace+get_classvà sử dụng phản xạ nhanh hơn khoảng 20% ​​so với sử dụng phương pháp tên cơ sở, nhưng YMMV.


0

Giải pháp nhanh nhất và imho dễ nhất hoạt động trong mọi môi trường là:

<?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
Đây là lý do tại sao tôi muốn PHP có các toán tử thông tin lớp bên trong. Khởi tạo một phản xạ bên ngoài để làm những gì đơn giản như $Object->__class->getShortName()thực sự khiến tôi bực mình về PHP. Cách tiếp cận của bạn hoạt động, nhưng bây giờ bạn đang đặt các phương thức cụ thể trong các lớp của mình chỉ để hiển thị những gì nên là một cấu trúc ngôn ngữ.
AgmLauncher

PHP mà không có chức năng bê tông trực tuyến (hay chúng ta nên gọi chúng là các hàm thủ tục) là không thể. Chúng ta hãy chờ PHP 6 (tốt, nếu nó đến).
F Meatgrinder

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

0

Nếu bạn chỉ tước bỏ không gian tên và muốn bất cứ thứ gì sau \ trong tên lớp có không gian tên (hoặc chỉ tên nếu không có '\'), bạn có thể làm một cái gì đó như thế này:

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

Về cơ bản, nó là regex để có được bất kỳ sự kết hợp nào của các ký tự hoặc dấu gạch chéo ngược và cho đến dấu gạch chéo ngược cuối cùng sau đó chỉ trả lại các ký tự không dấu gạch chéo ngược lên và cho đến hết chuỗi. Thêm? sau khi nhóm đầu tiên có nghĩa là nếu khớp mẫu không tồn tại, nó chỉ trả về chuỗi đầy đủ.


0

Nhanh nhất mà tôi tìm thấy ở đây cho PHP 7.2vàoUbubntu 18.04

preg_replace('/^(\w+\\\)*/', '', static::class)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.