Skip to content
Snippets Groups Projects

Implement `::class` static property

This property contains the name of the class in PHP. In the second commit, I also added very barebones namespace tracking, so the class property can be resolved correctly for classes inside namespaces.

See https://secure.php.net/manual/en/language.oop5.basic.php#language.oop5.basic.class.class

This conflicts with !2 (merged), I'll rebase if one of these get merged :)

// input
class Foo {}
namespace Bar { class Xyz {} }
Foo::class;
// output
class Foo {
  static class = "Foo";
};
{//Bar
  class Xyz {
    static class = "Bar\\Xyz";
  };
}
Foo.class;

Merge request reports

Loading
Loading

Activity

Filter activity
  • Approvals
  • Assignees & reviewers
  • Comments (from bots)
  • Comments (from users)
  • Commits & branches
  • Edits
  • Labels
  • Lock status
  • Mentions
  • Merge request status
  • Tracking
  • Thanks for the PR.

    My concern is that it's noisy and modifies all classes, even in code that doesn't use that feature.

    Is it supposed to work dynamically like $foo::class or $this::class? If not, then instead of making an actual property, you could replace occurrences of Foo + :: + class with string literal "Foo".

  • Yeah, it is very noisy :( Late-binding static::class does work unfortunately.

    <?php
    class A {
      static function xyz () {
        return static::class;
      }
    }
    class B extends A {}
    
    echo A::xyz(); // 'A'
    echo B::xyz(); // 'B'

    A less noisy way is using the JavaScript .name property on the constructor function, but that wouldn't include namespace names correctly…

    One idea is to give the class a name that includes the namespace:

    // Input
    namespace Hello {
      class Greeting {
        public static function show () {
          echo static::class;
        }
      }
      class World extends Greeting {}
    }
    namespace {
      Hello\World::show();
    }
    // Output
    {// Hello
      const Greeting = class Hello$Greeting {
        static show () {
          // ::class → .name.replace(...)
          return this.name.replace(/\$/g, '\\')
        }
      }
      const World = class Hello$World extends Greeting {
      }
    }
    {//
      Hello.World.show()
    }

    Of course, namespaces aren't implemented yet, so the code won't run, but the result should be correct. Does that sound like a better implementation?

  • Could you use this.constructor.name?

Please register or sign in to reply
Loading