@@ -114,6 +114,17 @@ impl MethodArgs {
114114 }
115115}
116116
117+ /// A property getter or setter method.
118+ #[ derive( Debug ) ]
119+ struct PropertyMethod < ' a > {
120+ /// Property name in PHP (e.g., "name" for `get_name`/`set_name`).
121+ prop_name : String ,
122+ /// The Rust method identifier.
123+ method_ident : & ' a syn:: Ident ,
124+ /// Whether this is a getter (true) or setter (false).
125+ is_getter : bool ,
126+ }
127+
117128#[ derive( Debug ) ]
118129struct ParsedImpl < ' a > {
119130 path : & ' a syn:: Path ,
@@ -122,6 +133,8 @@ struct ParsedImpl<'a> {
122133 functions : Vec < FnBuilder > ,
123134 constructor : Option < ( Function < ' a > , Option < Visibility > ) > ,
124135 constants : Vec < Constant < ' a > > ,
136+ /// Property getter/setter methods.
137+ properties : Vec < PropertyMethod < ' a > > ,
125138}
126139
127140#[ derive( Debug , Eq , Hash , PartialEq ) ]
@@ -176,6 +189,7 @@ impl<'a> ParsedImpl<'a> {
176189 functions : Vec :: default ( ) ,
177190 constructor : Option :: default ( ) ,
178191 constants : Vec :: default ( ) ,
192+ properties : Vec :: default ( ) ,
179193 }
180194 }
181195
@@ -206,6 +220,32 @@ impl<'a> ParsedImpl<'a> {
206220 method. attrs . retain ( |attr| !attr. path ( ) . is_ident ( "php" ) ) ;
207221
208222 let opts = MethodArgs :: new ( name, attr) ;
223+
224+ // Handle getter/setter methods
225+ if matches ! ( opts. ty, MethodTy :: Getter | MethodTy :: Setter ) {
226+ let is_getter = matches ! ( opts. ty, MethodTy :: Getter ) ;
227+ // Extract property name by stripping get_/set_ prefix
228+ let method_name = method. sig . ident . to_string ( ) ;
229+ let prop_name = if is_getter {
230+ method_name
231+ . strip_prefix ( "get_" )
232+ . unwrap_or ( & method_name)
233+ . to_string ( )
234+ } else {
235+ method_name
236+ . strip_prefix ( "set_" )
237+ . unwrap_or ( & method_name)
238+ . to_string ( )
239+ } ;
240+
241+ self . properties . push ( PropertyMethod {
242+ prop_name,
243+ method_ident : & method. sig . ident ,
244+ is_getter,
245+ } ) ;
246+ continue ;
247+ }
248+
209249 let args = Args :: parse_from_fnargs ( method. sig . inputs . iter ( ) , opts. defaults ) ?;
210250 let mut func = Function :: new ( & method. sig , opts. name , args, opts. optional , docs) ;
211251
@@ -275,6 +315,59 @@ impl<'a> ParsedImpl<'a> {
275315 }
276316 } ) ;
277317
318+ // Group properties by name to combine getters and setters
319+ let mut prop_groups: HashMap < & str , ( Option < & syn:: Ident > , Option < & syn:: Ident > ) > =
320+ HashMap :: new ( ) ;
321+ for prop in & self . properties {
322+ let entry = prop_groups. entry ( & prop. prop_name ) . or_default ( ) ;
323+ if prop. is_getter {
324+ entry. 0 = Some ( prop. method_ident ) ;
325+ } else {
326+ entry. 1 = Some ( prop. method_ident ) ;
327+ }
328+ }
329+
330+ // Generate property creation code
331+ let property_inserts: Vec < TokenStream > = prop_groups
332+ . iter ( )
333+ . map ( |( prop_name, ( getter, setter) ) | {
334+ match ( getter, setter) {
335+ ( Some ( getter_ident) , Some ( setter_ident) ) => {
336+ // Both getter and setter - use combine
337+ quote ! {
338+ props. insert(
339+ #prop_name,
340+ :: ext_php_rs:: props:: Property :: method_getter( #path:: #getter_ident)
341+ . combine( :: ext_php_rs:: props:: Property :: method_setter( #path:: #setter_ident) )
342+ ) ;
343+ }
344+ }
345+ ( Some ( getter_ident) , None ) => {
346+ // Only getter
347+ quote ! {
348+ props. insert(
349+ #prop_name,
350+ :: ext_php_rs:: props:: Property :: method_getter( #path:: #getter_ident)
351+ ) ;
352+ }
353+ }
354+ ( None , Some ( setter_ident) ) => {
355+ // Only setter
356+ quote ! {
357+ props. insert(
358+ #prop_name,
359+ :: ext_php_rs:: props:: Property :: method_setter( #path:: #setter_ident)
360+ ) ;
361+ }
362+ }
363+ ( None , None ) => {
364+ // Should not happen
365+ quote ! { }
366+ }
367+ }
368+ } )
369+ . collect ( ) ;
370+
278371 quote ! {
279372 impl :: ext_php_rs:: internal:: class:: PhpClassImpl <#path>
280373 for :: ext_php_rs:: internal:: class:: PhpClassImplCollector <#path>
@@ -286,7 +379,9 @@ impl<'a> ParsedImpl<'a> {
286379 }
287380
288381 fn get_method_props<' a>( self ) -> :: std:: collections:: HashMap <& ' static str , :: ext_php_rs:: props:: Property <' a, #path>> {
289- todo!( )
382+ let mut props = :: std:: collections:: HashMap :: new( ) ;
383+ #( #property_inserts) *
384+ props
290385 }
291386
292387 fn get_constructor( self ) -> :: std:: option:: Option <:: ext_php_rs:: class:: ConstructorMeta <#path>> {
0 commit comments