Skip to content

Commit 6e5a294

Browse files
committed
add optional+required methods
1 parent 6dc477c commit 6e5a294

File tree

5 files changed

+285
-51
lines changed

5 files changed

+285
-51
lines changed

phper/src/functions.rs

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,9 @@ impl FunctionEntry {
191191
TypeHint::Object => Some(
192192
phper_zend_arg_info_with_type(arg.pass_by_ref, arg.name.as_ptr(), IS_OBJECT, arg.nullable)
193193
),
194-
/*TypeHint::Callable => {
195-
// Use ZEND_ARG_CALLABLE_INFO for callable typehint
196-
// You would need to implement this C function
197-
unsafe { phper_zend_arg_callable_info(arg.pass_by_ref, arg.name.as_ptr(), arg.nullable) }
198-
},*/
194+
TypeHint::Callable => Some(
195+
phper_zend_arg_info_with_type(arg.pass_by_ref, arg.name.as_ptr(), IS_CALLABLE, arg.nullable)
196+
),
199197
TypeHint::Iterable => {
200198
// For iterable typehint - this might need a special handler or could use IS_ITERABLE
201199
// if defined in your PHP version
@@ -206,35 +204,32 @@ impl FunctionEntry {
206204
// For PHP 8.0+, there might be a specific constant for mixed
207205
Some( phper_zend_arg_info_with_type(arg.pass_by_ref, arg.name.as_ptr(), 0, true) ) // 0 might be replaced with appropriate constant
208206
},
207+
TypeHint::ClassEntry(s) => {
208+
println!("typehint for class entry: {}", s);
209+
// Get the class name from the class entry
210+
/*let class_entry = f();
211+
let class_name = class_entry.get_name(); // Assuming get_name() returns a &str
212+
let temp_class_name = CString::new(class_name).unwrap();
213+
let class_name_c = Some(temp_class_name);
214+
215+
Some( phper_zend_arg_obj_info(
216+
arg.pass_by_ref,
217+
arg.name.as_ptr(),
218+
class_name_c.as_ref().unwrap().as_ptr(),
219+
arg.nullable
220+
))*/
221+
None
222+
},
223+
// everything from here is not relevant to function type-hints
209224
TypeHint::Void => {
210-
// Void type - typically only used for return values, not arguments
211-
Some( phper_zend_arg_info_with_type(arg.pass_by_ref, arg.name.as_ptr(), IS_VOID, false) )
225+
None
212226
},
213-
TypeHint::This => {
227+
TypeHint::_Self => {
214228
None
215-
// Some(phper_zend_arg_info(arg.pass_by_ref, arg.name.as_ptr()))
216229
},
217230
TypeHint::Never => {
218-
// Never return type - PHP 8.1+
219-
// This is typically only for return values
220-
Some( phper_zend_arg_info_with_type(arg.pass_by_ref, arg.name.as_ptr(), IS_NEVER, false) )
231+
None
221232
},
222-
/*TypeHint::ClassEntry(class_entry) => {
223-
// Get the class name from the class entry
224-
let class_name = class_entry.get_name(); // Assuming get_name() returns a &str
225-
let temp_class_name = CString::new(class_name).unwrap();
226-
class_name_c = Some(temp_class_name);
227-
228-
unsafe {
229-
phper_zend_arg_obj_info(
230-
arg.pass_by_ref,
231-
arg.name.as_ptr(),
232-
class_name_c.as_ref().unwrap().as_ptr(),
233-
arg.allow_null
234-
)
235-
}
236-
}*/
237-
_ => None
238233
}
239234
} else {
240235
None
@@ -457,6 +452,18 @@ impl Argument {
457452
self.nullable = true;
458453
self
459454
}
455+
456+
/// Argument is required (also see by_*<ref|val>)
457+
pub fn required(mut self) -> Self {
458+
self.required = true;
459+
self
460+
}
461+
462+
/// Argument is optional (also see by_<ref|val>_optional)
463+
pub fn optional(mut self) -> Self {
464+
self.required = false;
465+
self
466+
}
460467
}
461468

462469
/// Function or method return type.

phper/src/types.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
//! Apis relate to PHP types.
1212
1313
use crate::{
14-
classes::ClassEntry,
1514
sys::*,
1615
};
1716
use derive_more::From;
@@ -247,9 +246,9 @@ pub enum TypeHint {
247246
/// void typehint
248247
Void,
249248
/// self typehint
250-
This,
249+
_Self,
250+
/// ClassEntry typehint (class, interface)
251+
ClassEntry(String),
251252
/// never typehint (php 8.1+)
252253
Never,
253-
/// class entry typehint
254-
ClassEntry(ClassEntry),
255254
}

tests/integration/src/typehints.rs

Lines changed: 187 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
use phper::{
1212
classes::{
13-
ClassEntity, ClassEntry, Interface, InterfaceEntity, StateClass, Visibility,
13+
ClassEntity, Interface, InterfaceEntity, StateClass, Visibility,
1414
},
1515
functions::{Argument, ReturnType},
1616
modules::Module,
@@ -22,7 +22,7 @@ pub fn integrate(module: &mut Module) {
2222
let i_foo = module.add_interface(make_i_foo_interface());
2323
let a_class = module.add_class(make_foo_class(i_foo.clone()));
2424
let _b_class = module.add_class(make_b_class(a_class.clone(), i_foo.clone()));
25-
let _c_class = module.add_class(make_c_class());
25+
let _c_class = module.add_class(make_c_class(i_foo.clone()));
2626
}
2727

2828
fn make_i_foo_interface() -> InterfaceEntity {
@@ -80,41 +80,212 @@ fn make_b_class(
8080
.add_static_method("createFoo", Visibility::Public, move |_| {
8181
let object = a_class.init_object()?;
8282
Ok::<_, phper::Error>(object)
83-
}); //todo return ClassEntity(i_foo)
83+
});
8484

8585
class
8686
}
8787

88-
fn make_c_class() ->ClassEntity<()> {
88+
fn make_c_class(
89+
_i_foo: Interface,
90+
) ->ClassEntity<()> {
8991
let mut class = ClassEntity::new(r"IntegrationTest\TypeHints\C");
92+
// String tests
9093
class
91-
.add_method("exString", Visibility::Public, move |_, arguments| {
92-
let name = arguments[0].expect_z_str()?.to_str()?.to_string();
93-
phper::ok(name)
94+
.add_method("testString", Visibility::Public, move |_, arguments| {
95+
let _ = arguments[0].expect_z_str()?.to_str()?.to_string();
96+
phper::ok(())
9497
})
9598
.argument(Argument::by_val("string_value").with_type_hint(TypeHint::String));
9699

97100
class
98-
.add_method("exStringOptional", Visibility::Public, move |_, arguments| {
99-
let name = arguments[0].expect_z_str()?.to_str()?.to_string();
100-
phper::ok(name)
101+
.add_method("testStringOptional", Visibility::Public, move |_, arguments| {
102+
let _ = arguments[0].expect_z_str()?.to_str()?.to_string();
103+
phper::ok(())
104+
})
105+
.argument(Argument::by_val("string_value").with_type_hint(TypeHint::String).optional());
106+
107+
class
108+
.add_method("testStringNullable", Visibility::Public, move |_, arguments| {
109+
let _ = arguments[0].expect_z_str()?.to_str()?.to_string();
110+
phper::ok(())
101111
})
102112
.argument(Argument::by_val("string_value").with_type_hint(TypeHint::String).nullable());
103113

114+
// Bool tests
104115
class
105-
.add_method("exBool", Visibility::Public, move |_, arguments| {
106-
let name = arguments[0].as_bool();
107-
phper::ok(name)
116+
.add_method("testBool", Visibility::Public, move |_, arguments| {
117+
let _ = arguments[0].as_bool();
118+
phper::ok(())
108119
})
109120
.argument(Argument::by_val("bool_value").with_type_hint(TypeHint::Bool));
110121

111122
class
112-
.add_method("exBoolOptional", Visibility::Public, move |_, arguments| {
113-
let name = arguments[0].as_bool();
114-
phper::ok(name)
123+
.add_method("testBoolNullable", Visibility::Public, move |_, arguments| {
124+
let _ = arguments[0].as_bool();
125+
phper::ok(())
115126
})
116127
.argument(Argument::by_val("bool_value").with_type_hint(TypeHint::Bool).nullable());
117128

129+
class
130+
.add_method("testBoolOptional", Visibility::Public, move |_, arguments| {
131+
let _ = arguments[0].expect_bool()?;
132+
phper::ok(())
133+
})
134+
.argument(Argument::by_val("bool_value").with_type_hint(TypeHint::Bool).optional());
135+
136+
// Int tests
137+
class
138+
.add_method("testInt", Visibility::Public, move |_, arguments| {
139+
let _ = arguments[0].expect_long()?;
140+
phper::ok(())
141+
})
142+
.argument(Argument::by_val("int_value").with_type_hint(TypeHint::Int));
143+
144+
class
145+
.add_method("testIntNullable", Visibility::Public, move |_, arguments| {
146+
let _ = arguments[0].expect_long()?;
147+
phper::ok(())
148+
})
149+
.argument(Argument::by_val("int_value").with_type_hint(TypeHint::Int).nullable());
150+
151+
class
152+
.add_method("testIntOptional", Visibility::Public, move |_, arguments| {
153+
let _ = arguments[0].expect_long()?;
154+
phper::ok(())
155+
})
156+
.argument(Argument::by_val("int_value").with_type_hint(TypeHint::Int).optional());
157+
158+
// Float tests
159+
class
160+
.add_method("testFloat", Visibility::Public, move |_, arguments| {
161+
let _ = arguments[0].expect_double()?;
162+
phper::ok(())
163+
})
164+
.argument(Argument::by_val("float_value").with_type_hint(TypeHint::Float));
165+
166+
class
167+
.add_method("testFloatOptional", Visibility::Public, move |_, arguments| {
168+
let _ = arguments[0].expect_double()?;
169+
phper::ok(())
170+
})
171+
.argument(Argument::by_val("float_value").with_type_hint(TypeHint::Float).optional());
172+
173+
class
174+
.add_method("testFloatNullable", Visibility::Public, move |_, arguments| {
175+
let _ = arguments[0].expect_double()?;
176+
phper::ok(())
177+
})
178+
.argument(Argument::by_val("float_value").with_type_hint(TypeHint::Float).nullable());
179+
180+
// Array tests
181+
class
182+
.add_method("testArray", Visibility::Public, move |_, arguments| {
183+
let _ = arguments[0].expect_z_arr()?;
184+
phper::ok(())
185+
})
186+
.argument(Argument::by_val("array_value").with_type_hint(TypeHint::Array));
187+
188+
class
189+
.add_method("testArrayOptional", Visibility::Public, move |_, arguments| {
190+
let _ = arguments[0].expect_z_arr()?;
191+
phper::ok(())
192+
})
193+
.argument(Argument::by_val("array_value").with_type_hint(TypeHint::Array).optional());
194+
195+
class
196+
.add_method("testArrayNullable", Visibility::Public, move |_, arguments| {
197+
let _ = arguments[0].expect_z_arr()?;
198+
phper::ok(())
199+
})
200+
.argument(Argument::by_val("array_value").with_type_hint(TypeHint::Array).nullable());
201+
202+
// Mixed tests
203+
class
204+
.add_method("testMixed", Visibility::Public, move |_, _| {
205+
phper::ok(())
206+
})
207+
.argument(Argument::by_val("mixed_value").with_type_hint(TypeHint::Mixed));
208+
209+
// Callable tests
210+
class
211+
.add_method("testCallable", Visibility::Public, move |_, _| {
212+
phper::ok(())
213+
})
214+
.argument(Argument::by_val("callable_value").with_type_hint(TypeHint::Callable));
215+
216+
class
217+
.add_method("testCallableNullable", Visibility::Public, move |_, _| {
218+
phper::ok(())
219+
})
220+
.argument(Argument::by_val("callable_value").with_type_hint(TypeHint::Callable).nullable());
221+
222+
class
223+
.add_method("testCallableOptional", Visibility::Public, move |_, _| {
224+
phper::ok(())
225+
})
226+
.argument(Argument::by_val("callable_value").with_type_hint(TypeHint::Callable).optional());
227+
228+
class
229+
.add_method("testObject", Visibility::Public, move |_, _| {
230+
phper::ok(())
231+
})
232+
.argument(Argument::by_val("object_value").with_type_hint(TypeHint::Object));
233+
234+
class
235+
.add_method("testObjectNullable", Visibility::Public, move |_, _| {
236+
phper::ok(())
237+
})
238+
.argument(Argument::by_val("object_value").with_type_hint(TypeHint::Object).nullable());
239+
240+
class
241+
.add_method("testObjectOptional", Visibility::Public, move |_, _| {
242+
phper::ok(())
243+
})
244+
.argument(Argument::by_val("object_value").with_type_hint(TypeHint::Object).optional());
245+
246+
class
247+
.add_method("testIterable", Visibility::Public, move |_, _| {
248+
phper::ok(())
249+
})
250+
.argument(Argument::by_val("iterable_value").with_type_hint(TypeHint::Iterable));
251+
252+
class
253+
.add_method("testIterableNullable", Visibility::Public, move |_, _| {
254+
phper::ok(())
255+
})
256+
.argument(Argument::by_val("iterable_value").with_type_hint(TypeHint::Iterable).nullable());
257+
258+
class
259+
.add_method("testIterableOptional", Visibility::Public, move |_, _| {
260+
phper::ok(())
261+
})
262+
.argument(Argument::by_val("iterable_value").with_type_hint(TypeHint::Iterable).optional());
263+
264+
class
265+
.add_method("testNull", Visibility::Public, move |_, _| {
266+
phper::ok(())
267+
})
268+
.argument(Argument::by_val("null_value").with_type_hint(TypeHint::Null));
269+
270+
// Class type test (assuming you have a classEntry for "DateTime")
271+
class
272+
.add_method("testClassEntry", Visibility::Public, move |_, _| {
273+
phper::ok(())
274+
})
275+
.argument(Argument::by_val("classentry").with_type_hint(TypeHint::ClassEntry(String::from("todo"))));
276+
277+
/*class
278+
.add_method("testClassNullable", Visibility::Public, move |_, arguments| {
279+
if arguments[0].is_null() {
280+
phper::ok("null")
281+
} else {
282+
let obj = arguments[0].expect_z_obj()?;
283+
let class_name = obj.get_class_name()?;
284+
phper::ok(class_name)
285+
}
286+
})
287+
.argument(Argument::by_val("datetime_obj").with_type_hint(TypeHint::ClassEntry(get_date_time_class_entry())).nullable());*/
288+
118289

119290
class
120291
}

tests/integration/tests/php/_common.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ function assert_false($value) {
2828
assert_eq($value, false);
2929
}
3030

31-
function assert_eq($left, $right) {
31+
function assert_eq($left, $right, $message = '') {
3232
if ($left !== $right) {
33-
throw new AssertionError(sprintf("left != right,\n left: %s,\n right: %s", var_export($left, true), var_export($right, true)));
33+
throw new AssertionError(sprintf("left != right,\n left: %s,\n right: %s,\n message: %s,\n", var_export($left, true), var_export($right, true), $message));
3434
}
3535
}
3636

0 commit comments

Comments
 (0)