Skip to content

Commit 2e3e790

Browse files
committed
Introduce FFI::Scope class
This is a refactoring of user level ext/FFI API. The most important changes are in ``ffi.stub.php``. Now FFI::cdef, FFI::load and FFI::scope return an instance of new FFI\Scope class instead of FFI. There us no way to instantiate an object of class FFI. Methods FFI::new, FFI:cast, FFI::type may be called only statically. The deprecation introduced by https://wiki.php.net/rfc/ffi-non-static-deprecated is removed. FFI\Scope::new, FFI\Scope::cast, FFI\Scope::type can't be called as static methods. Most tests are not affcted by this change, but of course this may break some user code.
1 parent e34eebb commit 2e3e790

File tree

9 files changed

+129
-208
lines changed

9 files changed

+129
-208
lines changed

ext/ffi/ffi.c

+78-109
Original file line numberDiff line numberDiff line change
@@ -204,19 +204,17 @@ typedef struct _zend_ffi_ctype {
204204
static zend_class_entry *zend_ffi_exception_ce;
205205
static zend_class_entry *zend_ffi_parser_exception_ce;
206206
static zend_class_entry *zend_ffi_ce;
207+
static zend_class_entry *zend_ffi_scope_ce;
207208
static zend_class_entry *zend_ffi_cdata_ce;
208209
static zend_class_entry *zend_ffi_ctype_ce;
209210

210211
static zend_object_handlers zend_ffi_handlers;
212+
static zend_object_handlers zend_ffi_scope_handlers;
211213
static zend_object_handlers zend_ffi_cdata_handlers;
212214
static zend_object_handlers zend_ffi_cdata_value_handlers;
213215
static zend_object_handlers zend_ffi_cdata_free_handlers;
214216
static zend_object_handlers zend_ffi_ctype_handlers;
215217

216-
static zend_internal_function zend_ffi_new_fn;
217-
static zend_internal_function zend_ffi_cast_fn;
218-
static zend_internal_function zend_ffi_type_fn;
219-
220218
/* forward declarations */
221219
static void _zend_ffi_type_dtor(zend_ffi_type *type);
222220
static void zend_ffi_finalize_type(zend_ffi_dcl *dcl);
@@ -2279,7 +2277,7 @@ static HashTable *zend_ffi_ctype_get_debug_info(zend_object *obj, int *is_temp)
22792277
}
22802278
/* }}} */
22812279

2282-
static zend_object *zend_ffi_new(zend_class_entry *class_type) /* {{{ */
2280+
static zend_object *zend_ffi_scope_new(zend_class_entry *class_type) /* {{{ */
22832281
{
22842282
zend_ffi *ffi;
22852283

@@ -2415,7 +2413,7 @@ static void zend_ffi_scope_hash_dtor(zval *zv) /* {{{ */
24152413
}
24162414
/* }}} */
24172415

2418-
static void zend_ffi_free_obj(zend_object *object) /* {{{ */
2416+
static void zend_ffi_scope_free_obj(zend_object *object) /* {{{ */
24192417
{
24202418
zend_ffi *ffi = (zend_ffi*)object;
24212419

@@ -2475,7 +2473,7 @@ static zend_object *zend_ffi_cdata_clone_obj(zend_object *obj) /* {{{ */
24752473
}
24762474
/* }}} */
24772475

2478-
static zval *zend_ffi_read_var(zend_object *obj, zend_string *var_name, int read_type, void **cache_slot, zval *rv) /* {{{ */
2476+
static zval *zend_ffi_scope_read_var(zend_object *obj, zend_string *var_name, int read_type, void **cache_slot, zval *rv) /* {{{ */
24792477
{
24802478
zend_ffi *ffi = (zend_ffi*)obj;
24812479
zend_ffi_symbol *sym = NULL;
@@ -2518,7 +2516,7 @@ static zval *zend_ffi_read_var(zend_object *obj, zend_string *var_name, int read
25182516
}
25192517
/* }}} */
25202518

2521-
static zval *zend_ffi_write_var(zend_object *obj, zend_string *var_name, zval *value, void **cache_slot) /* {{{ */
2519+
static zval *zend_ffi_scope_write_var(zend_object *obj, zend_string *var_name, zval *value, void **cache_slot) /* {{{ */
25222520
{
25232521
zend_ffi *ffi = (zend_ffi*)obj;
25242522
zend_ffi_symbol *sym = NULL;
@@ -2870,30 +2868,17 @@ static ZEND_FUNCTION(ffi_trampoline) /* {{{ */
28702868
}
28712869
/* }}} */
28722870

2873-
static zend_function *zend_ffi_get_func(zend_object **obj, zend_string *name, const zval *key) /* {{{ */
2871+
static zend_function *zend_ffi_scope_get_func(zend_object **obj, zend_string *name, const zval *key) /* {{{ */
28742872
{
28752873
zend_ffi *ffi = (zend_ffi*)*obj;
28762874
zend_ffi_symbol *sym = NULL;
28772875
zend_function *func;
28782876
zend_ffi_type *type;
2877+
zval *zv;
28792878

2880-
if (ZSTR_LEN(name) == sizeof("new") -1
2881-
&& (ZSTR_VAL(name)[0] == 'n' || ZSTR_VAL(name)[0] == 'N')
2882-
&& (ZSTR_VAL(name)[1] == 'e' || ZSTR_VAL(name)[1] == 'E')
2883-
&& (ZSTR_VAL(name)[2] == 'w' || ZSTR_VAL(name)[2] == 'W')) {
2884-
return (zend_function*)&zend_ffi_new_fn;
2885-
} else if (ZSTR_LEN(name) == sizeof("cast") -1
2886-
&& (ZSTR_VAL(name)[0] == 'c' || ZSTR_VAL(name)[0] == 'C')
2887-
&& (ZSTR_VAL(name)[1] == 'a' || ZSTR_VAL(name)[1] == 'A')
2888-
&& (ZSTR_VAL(name)[2] == 's' || ZSTR_VAL(name)[2] == 'S')
2889-
&& (ZSTR_VAL(name)[3] == 't' || ZSTR_VAL(name)[3] == 'T')) {
2890-
return (zend_function*)&zend_ffi_cast_fn;
2891-
} else if (ZSTR_LEN(name) == sizeof("type") -1
2892-
&& (ZSTR_VAL(name)[0] == 't' || ZSTR_VAL(name)[0] == 'T')
2893-
&& (ZSTR_VAL(name)[1] == 'y' || ZSTR_VAL(name)[1] == 'Y')
2894-
&& (ZSTR_VAL(name)[2] == 'p' || ZSTR_VAL(name)[2] == 'P')
2895-
&& (ZSTR_VAL(name)[3] == 'e' || ZSTR_VAL(name)[3] == 'E')) {
2896-
return (zend_function*)&zend_ffi_type_fn;
2879+
zv = zend_hash_find(&zend_ffi_scope_ce->function_table, name);
2880+
if (zv) {
2881+
return (zend_function*)Z_PTR_P(zv);
28972882
}
28982883

28992884
if (ffi->symbols) {
@@ -3057,7 +3042,7 @@ ZEND_METHOD(FFI, cdef) /* {{{ */
30573042
}
30583043
}
30593044

3060-
ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3045+
ffi = (zend_ffi*)zend_ffi_scope_new(zend_ffi_scope_ce);
30613046
ffi->lib = handle;
30623047
ffi->symbols = FFI_G(symbols);
30633048
ffi->tags = FFI_G(tags);
@@ -3493,15 +3478,15 @@ static zend_ffi *zend_ffi_load(const char *filename, bool preload) /* {{{ */
34933478
}
34943479

34953480
if (EG(objects_store).object_buckets) {
3496-
ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3481+
ffi = (zend_ffi*)zend_ffi_scope_new(zend_ffi_scope_ce);
34973482
} else {
34983483
ffi = ecalloc(1, sizeof(zend_ffi));
34993484
}
35003485
ffi->symbols = scope->symbols;
35013486
ffi->tags = scope->tags;
35023487
ffi->persistent = 1;
35033488
} else {
3504-
ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3489+
ffi = (zend_ffi*)zend_ffi_scope_new(zend_ffi_scope_ce);
35053490
ffi->lib = handle;
35063491
ffi->symbols = FFI_G(symbols);
35073492
ffi->tags = FFI_G(tags);
@@ -3574,7 +3559,7 @@ ZEND_METHOD(FFI, scope) /* {{{ */
35743559
RETURN_THROWS();
35753560
}
35763561

3577-
ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3562+
ffi = (zend_ffi*)zend_ffi_scope_new(zend_ffi_scope_ce);
35783563

35793564
ffi->symbols = scope->symbols;
35803565
ffi->tags = scope->tags;
@@ -3753,7 +3738,7 @@ static void zend_ffi_tags_cleanup(zend_ffi_dcl *dcl) /* {{{ */
37533738
}
37543739
/* }}} */
37553740

3756-
ZEND_METHOD(FFI, new) /* {{{ */
3741+
static void _zend_ffi_new(INTERNAL_FUNCTION_PARAMETERS, bool is_static_call) /* {{{ */
37573742
{
37583743
zend_string *type_def = NULL;
37593744
zend_object *type_obj = NULL;
@@ -3763,7 +3748,6 @@ ZEND_METHOD(FFI, new) /* {{{ */
37633748
bool owned = 1;
37643749
bool persistent = 0;
37653750
bool is_const = 0;
3766-
bool is_static_call = Z_TYPE(EX(This)) != IS_OBJECT;
37673751
zend_ffi_flags flags = ZEND_FFI_FLAG_OWNED;
37683752

37693753
ZEND_FFI_VALIDATE_API_RESTRICTION();
@@ -3774,13 +3758,6 @@ ZEND_METHOD(FFI, new) /* {{{ */
37743758
Z_PARAM_BOOL(persistent)
37753759
ZEND_PARSE_PARAMETERS_END();
37763760

3777-
if (is_static_call) {
3778-
zend_error(E_DEPRECATED, "Calling FFI::new() statically is deprecated");
3779-
if (EG(exception)) {
3780-
RETURN_THROWS();
3781-
}
3782-
}
3783-
37843761
if (!owned) {
37853762
flags &= ~ZEND_FFI_FLAG_OWNED;
37863763
}
@@ -3878,6 +3855,18 @@ ZEND_METHOD(FFI, new) /* {{{ */
38783855
}
38793856
/* }}} */
38803857

3858+
ZEND_METHOD(FFI, new) /* {{{ */
3859+
{
3860+
_zend_ffi_new(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
3861+
}
3862+
/* }}} */
3863+
3864+
ZEND_METHOD(FFI_Scope, new) /* {{{ */
3865+
{
3866+
_zend_ffi_new(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
3867+
}
3868+
/* }}} */
3869+
38813870
ZEND_METHOD(FFI, free) /* {{{ */
38823871
{
38833872
zval *zv;
@@ -3912,14 +3901,13 @@ ZEND_METHOD(FFI, free) /* {{{ */
39123901
}
39133902
/* }}} */
39143903

3915-
ZEND_METHOD(FFI, cast) /* {{{ */
3904+
static void _zend_ffi_cast(INTERNAL_FUNCTION_PARAMETERS, bool is_static_call) /* {{{ */
39163905
{
39173906
zend_string *type_def = NULL;
39183907
zend_object *ztype = NULL;
39193908
zend_ffi_type *old_type, *type, *type_ptr;
39203909
zend_ffi_cdata *old_cdata, *cdata;
39213910
bool is_const = 0;
3922-
bool is_static_call = Z_TYPE(EX(This)) != IS_OBJECT;
39233911
zval *zv, *arg;
39243912
void *ptr;
39253913

@@ -3929,13 +3917,6 @@ ZEND_METHOD(FFI, cast) /* {{{ */
39293917
Z_PARAM_ZVAL(zv)
39303918
ZEND_PARSE_PARAMETERS_END();
39313919

3932-
if (is_static_call) {
3933-
zend_error(E_DEPRECATED, "Calling FFI::cast() statically is deprecated");
3934-
if (EG(exception)) {
3935-
RETURN_THROWS();
3936-
}
3937-
}
3938-
39393920
arg = zv;
39403921
ZVAL_DEREF(zv);
39413922

@@ -4095,25 +4076,29 @@ ZEND_METHOD(FFI, cast) /* {{{ */
40954076
}
40964077
/* }}} */
40974078

4098-
ZEND_METHOD(FFI, type) /* {{{ */
4079+
ZEND_METHOD(FFI, cast) /* {{{ */
4080+
{
4081+
_zend_ffi_cast(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
4082+
}
4083+
/* }}} */
4084+
4085+
ZEND_METHOD(FFI_Scope, cast) /* {{{ */
4086+
{
4087+
_zend_ffi_cast(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
4088+
}
4089+
/* }}} */
4090+
4091+
static void _zend_ffi_type(INTERNAL_FUNCTION_PARAMETERS, bool is_static_call) /* {{{ */
40994092
{
41004093
zend_ffi_ctype *ctype;
41014094
zend_ffi_dcl dcl = ZEND_FFI_ATTR_INIT;
41024095
zend_string *type_def;
4103-
bool is_static_call = Z_TYPE(EX(This)) != IS_OBJECT;
41044096

41054097
ZEND_FFI_VALIDATE_API_RESTRICTION();
41064098
ZEND_PARSE_PARAMETERS_START(1, 1)
41074099
Z_PARAM_STR(type_def);
41084100
ZEND_PARSE_PARAMETERS_END();
41094101

4110-
if (is_static_call) {
4111-
zend_error(E_DEPRECATED, "Calling FFI::type() statically is deprecated");
4112-
if (EG(exception)) {
4113-
RETURN_THROWS();
4114-
}
4115-
}
4116-
41174102
if (!is_static_call) {
41184103
zend_ffi *ffi = (zend_ffi*)Z_OBJ(EX(This));
41194104
FFI_G(symbols) = ffi->symbols;
@@ -4160,6 +4145,18 @@ ZEND_METHOD(FFI, type) /* {{{ */
41604145
}
41614146
/* }}} */
41624147

4148+
ZEND_METHOD(FFI, type) /* {{{ */
4149+
{
4150+
_zend_ffi_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
4151+
}
4152+
/* }}} */
4153+
4154+
ZEND_METHOD(FFI_Scope, type) /* {{{ */
4155+
{
4156+
_zend_ffi_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
4157+
}
4158+
/* }}} */
4159+
41634160
ZEND_METHOD(FFI, typeof) /* {{{ */
41644161
{
41654162
zval *zv, *arg;
@@ -5380,30 +5377,6 @@ static zend_result zend_ffi_preload(char *preload) /* {{{ */
53805377
}
53815378
/* }}} */
53825379

5383-
/* The startup code for observers adds a temporary to each function for internal use.
5384-
* The "new", "cast", and "type" functions in FFI are both static and non-static.
5385-
* Only the static versions are in the function table and the non-static versions are not.
5386-
* This means the non-static versions will be skipped by the observers startup code.
5387-
* This function fixes that by incrementing the temporary count for the non-static versions.
5388-
*/
5389-
static zend_result (*prev_zend_post_startup_cb)(void);
5390-
static zend_result ffi_fixup_temporaries(void) {
5391-
if (ZEND_OBSERVER_ENABLED) {
5392-
++zend_ffi_new_fn.T;
5393-
++zend_ffi_cast_fn.T;
5394-
++zend_ffi_type_fn.T;
5395-
}
5396-
#ifndef ZTS
5397-
ZEND_MAP_PTR(zend_ffi_new_fn.run_time_cache) = ZEND_MAP_PTR(((zend_internal_function *)zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "new", sizeof("new")-1))->run_time_cache);
5398-
ZEND_MAP_PTR(zend_ffi_cast_fn.run_time_cache) = ZEND_MAP_PTR(((zend_internal_function *)zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "cast", sizeof("cast")-1))->run_time_cache);
5399-
ZEND_MAP_PTR(zend_ffi_type_fn.run_time_cache) = ZEND_MAP_PTR(((zend_internal_function *)zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "type", sizeof("type")-1))->run_time_cache);
5400-
#endif
5401-
if (prev_zend_post_startup_cb) {
5402-
return prev_zend_post_startup_cb();
5403-
}
5404-
return SUCCESS;
5405-
}
5406-
54075380
/* {{{ ZEND_MINIT_FUNCTION */
54085381
ZEND_MINIT_FUNCTION(ffi)
54095382
{
@@ -5416,39 +5389,35 @@ ZEND_MINIT_FUNCTION(ffi)
54165389
zend_ffi_parser_exception_ce = register_class_FFI_ParserException(zend_ffi_exception_ce);
54175390

54185391
zend_ffi_ce = register_class_FFI();
5419-
zend_ffi_ce->create_object = zend_ffi_new;
54205392
zend_ffi_ce->default_object_handlers = &zend_ffi_handlers;
54215393

5422-
memcpy(&zend_ffi_new_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "new", sizeof("new")-1), sizeof(zend_internal_function));
5423-
zend_ffi_new_fn.fn_flags &= ~ZEND_ACC_STATIC;
5424-
memcpy(&zend_ffi_cast_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "cast", sizeof("cast")-1), sizeof(zend_internal_function));
5425-
zend_ffi_cast_fn.fn_flags &= ~ZEND_ACC_STATIC;
5426-
memcpy(&zend_ffi_type_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "type", sizeof("type")-1), sizeof(zend_internal_function));
5427-
zend_ffi_type_fn.fn_flags &= ~ZEND_ACC_STATIC;
5428-
5429-
prev_zend_post_startup_cb = zend_post_startup_cb;
5430-
zend_post_startup_cb = ffi_fixup_temporaries;
5394+
zend_ffi_scope_ce = register_class_FFI_Scope();
5395+
zend_ffi_scope_ce->create_object = zend_ffi_scope_new;
5396+
zend_ffi_scope_ce->default_object_handlers = &zend_ffi_scope_handlers;
54315397

54325398
memcpy(&zend_ffi_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
54335399
zend_ffi_handlers.get_constructor = zend_fake_get_constructor;
5434-
zend_ffi_handlers.free_obj = zend_ffi_free_obj;
5435-
zend_ffi_handlers.clone_obj = NULL;
5436-
zend_ffi_handlers.read_property = zend_ffi_read_var;
5437-
zend_ffi_handlers.write_property = zend_ffi_write_var;
5438-
zend_ffi_handlers.read_dimension = zend_fake_read_dimension;
5439-
zend_ffi_handlers.write_dimension = zend_fake_write_dimension;
5440-
zend_ffi_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5441-
zend_ffi_handlers.has_property = zend_fake_has_property;
5442-
zend_ffi_handlers.unset_property = zend_fake_unset_property;
5443-
zend_ffi_handlers.has_dimension = zend_fake_has_dimension;
5444-
zend_ffi_handlers.unset_dimension = zend_fake_unset_dimension;
5445-
zend_ffi_handlers.get_method = zend_ffi_get_func;
5446-
zend_ffi_handlers.compare = NULL;
5447-
zend_ffi_handlers.cast_object = zend_fake_cast_object;
5448-
zend_ffi_handlers.get_debug_info = NULL;
5449-
zend_ffi_handlers.get_closure = NULL;
5450-
zend_ffi_handlers.get_properties = zend_fake_get_properties;
5451-
zend_ffi_handlers.get_gc = zend_fake_get_gc;
5400+
5401+
memcpy(&zend_ffi_scope_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5402+
zend_ffi_scope_handlers.get_constructor = zend_fake_get_constructor;
5403+
zend_ffi_scope_handlers.free_obj = zend_ffi_scope_free_obj;
5404+
zend_ffi_scope_handlers.clone_obj = NULL;
5405+
zend_ffi_scope_handlers.read_property = zend_ffi_scope_read_var;
5406+
zend_ffi_scope_handlers.write_property = zend_ffi_scope_write_var;
5407+
zend_ffi_scope_handlers.read_dimension = zend_fake_read_dimension;
5408+
zend_ffi_scope_handlers.write_dimension = zend_fake_write_dimension;
5409+
zend_ffi_scope_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5410+
zend_ffi_scope_handlers.has_property = zend_fake_has_property;
5411+
zend_ffi_scope_handlers.unset_property = zend_fake_unset_property;
5412+
zend_ffi_scope_handlers.has_dimension = zend_fake_has_dimension;
5413+
zend_ffi_scope_handlers.unset_dimension = zend_fake_unset_dimension;
5414+
zend_ffi_scope_handlers.get_method = zend_ffi_scope_get_func;
5415+
zend_ffi_scope_handlers.compare = NULL;
5416+
zend_ffi_scope_handlers.cast_object = zend_fake_cast_object;
5417+
zend_ffi_scope_handlers.get_debug_info = NULL;
5418+
zend_ffi_scope_handlers.get_closure = NULL;
5419+
zend_ffi_scope_handlers.get_properties = zend_fake_get_properties;
5420+
zend_ffi_scope_handlers.get_gc = zend_fake_get_gc;
54525421

54535422
zend_ffi_cdata_ce = register_class_FFI_CData();
54545423
zend_ffi_cdata_ce->create_object = zend_ffi_cdata_new;

ext/ffi/ffi.stub.php

+16-3
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ final class FFI
99
/** @cvalue __BIGGEST_ALIGNMENT__ */
1010
public const int __BIGGEST_ALIGNMENT__ = UNKNOWN;
1111

12-
public static function cdef(string $code = "", ?string $lib = null): FFI {}
12+
public static function cdef(string $code = "", ?string $lib = null): FFI\Scope {}
1313

14-
public static function load(string $filename): ?FFI {}
14+
public static function load(string $filename): ?FFI\Scope {}
1515

16-
public static function scope(string $name): FFI {}
16+
public static function scope(string $name): FFI\Scope {}
1717

1818
public static function new(FFI\CType|string $type, bool $owned = true, bool $persistent = false): FFI\CData {}
1919

@@ -71,6 +71,19 @@ public static function isNull(FFI\CData $ptr): bool {}
7171

7272
namespace FFI {
7373

74+
/** @not-serializable */
75+
final class Scope {
76+
public function new(CType|string $type, bool $owned = true, bool $persistent = false): CData {}
77+
78+
/**
79+
* @param CData|int|float|bool|null $ptr
80+
* @prefer-ref $ptr
81+
*/
82+
public function cast(CType|string $type, $ptr): CData {}
83+
84+
public function type(string $type): CType {}
85+
}
86+
7487
/** @not-serializable */
7588
final class CData {
7689
}

0 commit comments

Comments
 (0)