@@ -116,6 +116,17 @@ impl MethodArgs {
116116 }
117117}
118118
119+ /// A property getter or setter method.
120+ #[ derive( Debug ) ]
121+ struct PropertyMethod < ' a > {
122+ /// Property name in PHP (e.g., "name" for `get_name`/`set_name`).
123+ prop_name : String ,
124+ /// The Rust method identifier.
125+ method_ident : & ' a syn:: Ident ,
126+ /// Whether this is a getter (true) or setter (false).
127+ is_getter : bool ,
128+ }
129+
119130#[ derive( Debug ) ]
120131struct ParsedImpl < ' a > {
121132 path : & ' a syn:: Path ,
@@ -124,6 +135,8 @@ struct ParsedImpl<'a> {
124135 functions : Vec < FnBuilder > ,
125136 constructor : Option < ( Function < ' a > , Option < Visibility > ) > ,
126137 constants : Vec < Constant < ' a > > ,
138+ /// Property getter/setter methods.
139+ properties : Vec < PropertyMethod < ' a > > ,
127140}
128141
129142#[ derive( Debug , Eq , Hash , PartialEq ) ]
@@ -178,6 +191,7 @@ impl<'a> ParsedImpl<'a> {
178191 functions : Vec :: default ( ) ,
179192 constructor : Option :: default ( ) ,
180193 constants : Vec :: default ( ) ,
194+ properties : Vec :: default ( ) ,
181195 }
182196 }
183197
@@ -211,6 +225,32 @@ impl<'a> ParsedImpl<'a> {
211225 method. attrs . retain ( |attr| !attr. path ( ) . is_ident ( "php" ) ) ;
212226
213227 let opts = MethodArgs :: new ( name, attr) ;
228+
229+ // Handle getter/setter methods
230+ if matches ! ( opts. ty, MethodTy :: Getter | MethodTy :: Setter ) {
231+ let is_getter = matches ! ( opts. ty, MethodTy :: Getter ) ;
232+ // Extract property name by stripping get_/set_ prefix
233+ let method_name = method. sig . ident . to_string ( ) ;
234+ let prop_name = if is_getter {
235+ method_name
236+ . strip_prefix ( "get_" )
237+ . unwrap_or ( & method_name)
238+ . to_string ( )
239+ } else {
240+ method_name
241+ . strip_prefix ( "set_" )
242+ . unwrap_or ( & method_name)
243+ . to_string ( )
244+ } ;
245+
246+ self . properties . push ( PropertyMethod {
247+ prop_name,
248+ method_ident : & method. sig . ident ,
249+ is_getter,
250+ } ) ;
251+ continue ;
252+ }
253+
214254 let args = Args :: parse_from_fnargs ( method. sig . inputs . iter ( ) , opts. defaults ) ?;
215255 let mut func = Function :: new ( & method. sig , opts. name , args, opts. optional , docs) ;
216256
@@ -280,6 +320,59 @@ impl<'a> ParsedImpl<'a> {
280320 }
281321 } ) ;
282322
323+ // Group properties by name to combine getters and setters
324+ let mut prop_groups: HashMap < & str , ( Option < & syn:: Ident > , Option < & syn:: Ident > ) > =
325+ HashMap :: new ( ) ;
326+ for prop in & self . properties {
327+ let entry = prop_groups. entry ( & prop. prop_name ) . or_default ( ) ;
328+ if prop. is_getter {
329+ entry. 0 = Some ( prop. method_ident ) ;
330+ } else {
331+ entry. 1 = Some ( prop. method_ident ) ;
332+ }
333+ }
334+
335+ // Generate property creation code
336+ let property_inserts: Vec < TokenStream > = prop_groups
337+ . iter ( )
338+ . map ( |( prop_name, ( getter, setter) ) | {
339+ match ( getter, setter) {
340+ ( Some ( getter_ident) , Some ( setter_ident) ) => {
341+ // Both getter and setter - use combine
342+ quote ! {
343+ props. insert(
344+ #prop_name,
345+ :: ext_php_rs:: props:: Property :: method_getter( #path:: #getter_ident)
346+ . combine( :: ext_php_rs:: props:: Property :: method_setter( #path:: #setter_ident) )
347+ ) ;
348+ }
349+ }
350+ ( Some ( getter_ident) , None ) => {
351+ // Only getter
352+ quote ! {
353+ props. insert(
354+ #prop_name,
355+ :: ext_php_rs:: props:: Property :: method_getter( #path:: #getter_ident)
356+ ) ;
357+ }
358+ }
359+ ( None , Some ( setter_ident) ) => {
360+ // Only setter
361+ quote ! {
362+ props. insert(
363+ #prop_name,
364+ :: ext_php_rs:: props:: Property :: method_setter( #path:: #setter_ident)
365+ ) ;
366+ }
367+ }
368+ ( None , None ) => {
369+ // Should not happen
370+ quote ! { }
371+ }
372+ }
373+ } )
374+ . collect ( ) ;
375+
283376 quote ! {
284377 impl :: ext_php_rs:: internal:: class:: PhpClassImpl <#path>
285378 for :: ext_php_rs:: internal:: class:: PhpClassImplCollector <#path>
@@ -291,7 +384,9 @@ impl<'a> ParsedImpl<'a> {
291384 }
292385
293386 fn get_method_props<' a>( self ) -> :: std:: collections:: HashMap <& ' static str , :: ext_php_rs:: props:: Property <' a, #path>> {
294- todo!( )
387+ let mut props = :: std:: collections:: HashMap :: new( ) ;
388+ #( #property_inserts) *
389+ props
295390 }
296391
297392 fn get_constructor( self ) -> :: std:: option:: Option <:: ext_php_rs:: class:: ConstructorMeta <#path>> {
0 commit comments