@@ -30,8 +30,9 @@ pub struct StructAttributes {
3030 attrs : Vec < Attribute > ,
3131}
3232
33- /// Represents a class entry reference, either explicit (with `ce` and `stub`)
34- /// or a simple type reference to a Rust type implementing `RegisteredClass`.
33+ /// Represents a class entry reference, either explicit (with `ce` and `stub`),
34+ /// a simple type reference to a Rust type implementing `RegisteredClass`,
35+ /// or a string literal for runtime class lookup.
3536///
3637/// # Examples
3738///
@@ -44,13 +45,20 @@ pub struct StructAttributes {
4445/// ```ignore
4546/// #[php(extends(Base))]
4647/// ```
48+ ///
49+ /// String literal form (for runtime class lookup):
50+ /// ```ignore
51+ /// #[php(implements("\\JsonSerializable"))]
52+ /// ```
4753#[ derive( Debug ) ]
4854pub enum ClassEntryAttribute {
4955 /// Explicit class entry with a function returning `&'static ClassEntry` and
5056 /// a stub name
5157 Explicit { ce : syn:: Expr , stub : String } ,
5258 /// A Rust type that implements `RegisteredClass`
5359 Type ( syn:: Path ) ,
60+ /// A PHP class name to be looked up at runtime via `ClassEntry::try_find`
61+ Name ( String ) ,
5462}
5563
5664impl FromMeta for ClassEntryAttribute {
@@ -73,10 +81,15 @@ impl FromMeta for ClassEntryAttribute {
7381 stub : explicit. stub ,
7482 } )
7583 } else {
84+ // Try to parse as string literal first: implements("\\JsonSerializable")
85+ if let Ok ( lit) = list. parse_args :: < syn:: LitStr > ( ) {
86+ return Ok ( ClassEntryAttribute :: Name ( lit. value ( ) ) ) ;
87+ }
7688 // Parse as simple type form: extends(TypeName)
7789 let path: syn:: Path = list. parse_args ( ) . map_err ( |e| {
7890 darling:: Error :: custom ( format ! (
79- "Expected a type path (e.g., `MyClass`) or explicit form \
91+ "Expected a type path (e.g., `MyClass`), string literal \
92+ (e.g., `\" \\ \\ JsonSerializable\" `), or explicit form \
8093 (e.g., `ce = expr, stub = \" Name\" `): {e}"
8194 ) )
8295 } ) ?;
@@ -105,6 +118,17 @@ impl ToTokens for ClassEntryAttribute {
105118 )
106119 }
107120 }
121+ ClassEntryAttribute :: Name ( name) => {
122+ // For a string literal, generate a function that looks up the class at runtime
123+ // Uses try_find_no_autoload to avoid triggering autoloading during MINIT
124+ quote ! {
125+ (
126+ || :: ext_php_rs:: zend:: ClassEntry :: try_find_no_autoload( #name)
127+ . expect( concat!( "Failed to find class entry for " , #name) ) ,
128+ #name
129+ )
130+ }
131+ }
108132 } ;
109133 tokens. append_all ( token) ;
110134 }
0 commit comments