From d34724c6946f8d595394a09fa95767f51e5dde30 Mon Sep 17 00:00:00 2001 From: Dusan Malusev Date: Mon, 24 Jun 2024 22:07:01 +0200 Subject: [PATCH] Working on Classes Signed-off-by: Dusan Malusev --- examples/complex/config.m4 | 70 +++++++++++++++++++++++++++ examples/complex/package.xml | 64 +++++++++++++++++++++++++ examples/complex/src/lib.rs | 73 ++++++++++++++--------------- examples/complex/tests/php/test.php | 25 +++++----- examples/hello/config.m4 | 1 + examples/hello/package.xml | 9 ++-- phper-build/php_args_bindings.c | 17 +++++++ phper-build/php_args_bindings.h | 5 ++ phper/src/classes/entity.rs | 2 +- phper/src/ini/ini.rs | 23 ++++----- phper/src/modules/mod.rs | 2 +- 11 files changed, 222 insertions(+), 69 deletions(-) create mode 100644 examples/complex/config.m4 create mode 100644 examples/complex/package.xml create mode 100644 phper-build/php_args_bindings.c create mode 100644 phper-build/php_args_bindings.h diff --git a/examples/complex/config.m4 b/examples/complex/config.m4 new file mode 100644 index 00000000..34465fe3 --- /dev/null +++ b/examples/complex/config.m4 @@ -0,0 +1,70 @@ +dnl Copyright (c) 2022 PHPER Framework Team +dnl PHPER is licensed under Mulan PSL v2. +dnl You can use this software according to the terms and conditions of the Mulan +dnl PSL v2. You may obtain a copy of Mulan PSL v2 at: +dnl http://license.coscl.org.cn/MulanPSL2 +dnl THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +dnl KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +dnl NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +dnl See the Mulan PSL v2 for more details. + +PHP_ARG_ENABLE([complex], + [whether to enable hello support], + [AS_HELP_STRING([--enable-complex], + [Enable complex support])], + [no]) + +dnl If not enable, `cargo build` run with argument `--release`. +PHP_ARG_ENABLE([cargo_debug], [whether to enable cargo debug mode], +[ --enable-cargo-debug Enable cargo debug], no, no) + +if test "$PHP_hello" != "no"; then + dnl Check cargo command exists or not. + AC_PATH_PROG(CARGO, cargo, no) + if ! test -x "$CARGO"; then + AC_MSG_ERROR([cargo command missing, please reinstall the cargo distribution]) + fi + + AC_DEFINE(HAVE_complex, 1, [ Have complex support ]) + + PHP_NEW_EXTENSION(complex, [ ], $ext_shared) + + CARGO_MODE_FLAGS="--release" + CARGO_MODE_DIR="release" + + if test "$PHP_CARGO_DEBUG" != "no"; then + CARGO_MODE_FLAGS="" + CARGO_MODE_DIR="debug" + fi + + cat >>Makefile.objects<< EOF +all: cargo_build + +clean: cargo_clean + +cargo_build: + # Build the extension file + PHP_CONFIG=$PHP_PHP_CONFIG cargo build $CARGO_MODE_FLAGS + + # Copy the extension file from target dir to modules + if [[ -f ./target/$CARGO_MODE_DIR/libcomplex.dylib ]] ; then \\ + cp ./target/$CARGO_MODE_DIR/libcomplex.dylib ./modules/complex.so ; fi + if [[ -f ./target/$CARGO_MODE_DIR/libcomplex.so ]] ; then \\ + cp ./target/$CARGO_MODE_DIR/libcomplex.so ./modules/complex.so ; fi + +cargo_clean: + cargo clean + +.PHONY: cargo_build cargo_clean +EOF + + dnl Symbolic link the files for `cargo build` + AC_CONFIG_LINKS([ \ + Cargo.lock:Cargo.lock \ + Cargo.toml:Cargo.toml \ + build.rs:build.rs \ + stubs:stubs \ + src:src \ + tests:tests \ + ]) +fi diff --git a/examples/complex/package.xml b/examples/complex/package.xml new file mode 100644 index 00000000..c047bb29 --- /dev/null +++ b/examples/complex/package.xml @@ -0,0 +1,64 @@ + + + + complex + pecl.php.net + Hello world example a bit complex. + The Hello world example of phper. + + jmjoy + jmjoy + jmjoy@apache.org + yes + + 1970-01-01 + + 0.0.0 + 0.0.0 + + + stable + stable + + MulanPSL-2.0 + Release notes. + + + + + + + + + + + + + + + + 8.1.0 + + + 1.4.0 + + + + complex + + + + diff --git a/examples/complex/src/lib.rs b/examples/complex/src/lib.rs index 323354e8..5828c5a4 100644 --- a/examples/complex/src/lib.rs +++ b/examples/complex/src/lib.rs @@ -27,10 +27,7 @@ use phper::objects::StateObj; use phper::{modules::Module, php_get_module, values::ZVal, zend_args}; fn say_hello(arguments: &mut [ZVal]) -> phper::Result { - let name = &mut arguments[0]; - name.convert_to_string(); - let name = name.as_z_str().unwrap().to_str()?; - + let name = arguments[0].as_z_str().unwrap().to_str()?; Ok(format!("Hello, {name}!\n")) } @@ -47,14 +44,14 @@ pub fn get_module() -> Module { ); // register module ini - module.add_ini("complex.enable", false, Policy::All); - module.add_ini("complex.num", 100, Policy::All); - module.add_ini("complex.ratio", 1.5, Policy::All); - module.add_ini( - "complex.description", - "hello world.".to_owned(), - Policy::All, - ); + // module.add_ini("complex.enable", false, Policy::All); + // module.add_ini("complex.num", 100, Policy::All); + // module.add_ini("complex.ratio", 1.5, Policy::All); + // module.add_ini( + // "complex.description", + // "hello world.".to_owned(), + // Policy::All, + // ); // register hook functions module.on_module_init(|_info| {}); @@ -66,13 +63,13 @@ pub fn get_module() -> Module { "Complex\\say_hello", zend_args!(arginfo_Complex_say_hello), say_hello, + ) + .add_function( + "Complex\\throw_exception", + zend_args!(arginfo_Complex_throw_exception), + throw_exception, ); // .add_function( - // "Complex\\throw_exception", - // zend_args!(arginfo_Complex_throw_exception), - // throw_exception, - // ) - // .add_function( // "Complex\\get_all_ini", // zend_args!(arginfo_Complex_get_all_ini), // |_: &mut [ZVal]| { @@ -83,30 +80,30 @@ pub fn get_module() -> Module { // // let complex_description = // ZVal::from(ini_get::>("complex.description")); - // arr.insert("complex.description", complex_description); - // Ok::<_, Infallible>(arr) - // }, - // ); - // - // let mut foo_class = ClassEntity::new(CLASS_COMPLEX_FOO); - // - // foo_class.add_method( - // |this: &mut StateObj, _: &mut [ZVal]| { - // Ok::<_, phper::Error>(this.get_property("foo").clone()) + // arr.insert("complex.description",complex_description); + // Ok::<_, Infallible>(arr.clone()) // }, - // MethodEntityBuilder::new("getFoo", zend_args!(arginfo_class_Complex_Foo_getFoo)) - // .set_public(), // ); // - // foo_class.add_method( - // |this: &mut StateObj, arguments: &mut [ZVal]| -> phper::Result<()> { - // this.set_property("foo", arguments[0].clone()); - // Ok(()) - // }, - // MethodEntityBuilder::new("setFoo", zend_args!(arginfo_class_Complex_Foo_setFoo)) - // .set_public(), - // ); - // module.add_class(foo_class); + let mut foo_class = ClassEntity::new(CLASS_COMPLEX_FOO); + + foo_class.add_method( + |this: &mut StateObj, _: &mut [ZVal]| { + Ok::<_, phper::Error>(this.get_property("foo").clone()) + }, + MethodEntityBuilder::new("getFoo", zend_args!(arginfo_class_Complex_Foo_getFoo)) + .set_public(), + ); + + foo_class.add_method( + |this: &mut StateObj, arguments: &mut [ZVal]| -> phper::Result<()> { + this.set_property("foo", arguments[0].clone()); + Ok(()) + }, + MethodEntityBuilder::new("setFoo", zend_args!(arginfo_class_Complex_Foo_setFoo)) + .set_public(), + ); + module.add_class(foo_class); module.add_info("extra info key", "extra info value"); diff --git a/examples/complex/tests/php/test.php b/examples/complex/tests/php/test.php index a421d548..afecd72c 100644 --- a/examples/complex/tests/php/test.php +++ b/examples/complex/tests/php/test.php @@ -15,26 +15,23 @@ ini_set("display_startup_errors", "On"); error_reporting(E_ALL); -// print_r(get_defined_functions()); -// print_r(ini_get_all()); assert_eq(Complex\say_hello("world"), "Hello, world!\n"); -// -// try { -// Complex\throw_exception(); -// } catch (ErrorException $e) { -// assert_eq($e->getMessage(), "I am sorry"); -// } -// + +try { + Complex\throw_exception(); +} catch (ErrorException $e) { + assert_eq($e->getMessage(), "I am sorry"); +} + // assert_eq(Complex\get_all_ini(), [ // "complex.enable" => false, // "complex.description" => "hello world.", // ]); -// $foo = new Complex\\FooClass(); -// assert_eq($foo->getFoo(), 100); -// -// $foo->setFoo(200); -// assert_eq($foo->getFoo(), 200); +$foo = new Complex\Foo(); +assert_eq($foo->getFoo(), 100); +$foo->setFoo(200); +assert_eq($foo->getFoo(), 200); function assert_eq($left, $right) { if ($left !== $right) { diff --git a/examples/hello/config.m4 b/examples/hello/config.m4 index 34d9b826..83f17a2a 100644 --- a/examples/hello/config.m4 +++ b/examples/hello/config.m4 @@ -64,5 +64,6 @@ EOF Cargo.toml:Cargo.toml \ build.rs:build.rs \ src:src \ + stubs:stubs \ ]) fi diff --git a/examples/hello/package.xml b/examples/hello/package.xml index d188f1fb..581fe87d 100644 --- a/examples/hello/package.xml +++ b/examples/hello/package.xml @@ -10,9 +10,9 @@ KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the Mulan PSL v2 for more details. --> - hello pecl.php.net @@ -43,12 +43,13 @@ See the Mulan PSL v2 for more details. + - 7.2.0 + 8.1.0 1.4.0 diff --git a/phper-build/php_args_bindings.c b/phper-build/php_args_bindings.c new file mode 100644 index 00000000..cbc75856 --- /dev/null +++ b/phper-build/php_args_bindings.c @@ -0,0 +1,17 @@ +#include + +BEGIN_EXTERN_C() +#define static + +/* This is a generated file, edit the .stub.php file instead. +* Stub hash: 06df13993563e31f9f0fecc3b09978b926a9fda6 */ + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_hello, 0, 1, IS_STRING, 0) +ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) +ZEND_END_ARG_INFO() + + + + +#undef static +END_EXTERN_C() diff --git a/phper-build/php_args_bindings.h b/phper-build/php_args_bindings.h new file mode 100644 index 00000000..df656932 --- /dev/null +++ b/phper-build/php_args_bindings.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +extern const zend_internal_arg_info arginfo_hello[2]; diff --git a/phper/src/classes/entity.rs b/phper/src/classes/entity.rs index b2e9a6aa..f80a8443 100644 --- a/phper/src/classes/entity.rs +++ b/phper/src/classes/entity.rs @@ -184,7 +184,7 @@ impl crate::modules::Registerer for ClassEntity { let class_ce = phper_register_class_entry( Some(self.class_create), - methods.as_ptr().cast(), + Box::into_raw(methods.into_boxed_slice()).cast(), Some(create_object), ); diff --git a/phper/src/ini/ini.rs b/phper/src/ini/ini.rs index 557b1ab6..4f3b21cd 100644 --- a/phper/src/ini/ini.rs +++ b/phper/src/ini/ini.rs @@ -11,6 +11,7 @@ //! Apis relate to [zend_ini_entry_def]. use crate::{c_str, strings::ZString}; +use std::ffi::CString; use std::{ ffi::{c_int, c_uchar, c_void, CStr}, mem::zeroed, @@ -272,16 +273,17 @@ type ZendOnModify = unsafe extern "C" fn( pub(crate) fn create_ini_entry_ex( name: impl AsRef, - default_value: impl AsRef, + default_value: String, modifiable: u32, on_modify_impl: Option, ) -> zend_ini_entry_def where T: OnModify, { - let name = name.as_ref(); - let default_value = default_value.as_ref(); - let (modifiable, name_length) = (modifiable as c_uchar, name.len() as u16); + let name_length = name.as_ref().len(); + let name = CString::new(name.as_ref()).unwrap().into_raw(); + let default_value_len = default_value.len(); + let default_value = CString::new(default_value).unwrap_or_default().into_raw(); let (callback, arg): (Option, *mut OnModifyCarry) = match on_modify_impl { Some(callback) => ( @@ -294,22 +296,21 @@ where }; zend_ini_entry_def { - name: name.as_ptr().cast(), - name_length, + name, + name_length: name_length as u16, on_modify: callback, mh_arg1: arg as *mut c_void, mh_arg2: null_mut(), mh_arg3: null_mut(), - value: default_value.as_ptr().cast(), - value_length: default_value.len() as u32, + value: default_value, + value_length: default_value_len as u32, displayer: None, - modifiable, + modifiable: modifiable as c_uchar, } } unsafe fn entries(mut ini_entries: Vec) -> *const zend_ini_entry_def { - ini_entries.push(zeroed::()); - + ini_entries.push(zeroed()); Box::into_raw(ini_entries.into_boxed_slice()).cast() } diff --git a/phper/src/modules/mod.rs b/phper/src/modules/mod.rs index c5c1e3ce..2d2d4cad 100644 --- a/phper/src/modules/mod.rs +++ b/phper/src/modules/mod.rs @@ -186,7 +186,7 @@ impl Module { policy: ini::Policy, ) -> &mut Self { let ini = ini::create_ini_entry_ex( - name.as_ref(), + name, default_value.into_ini_value(), policy as u32, Option::<()>::None,