Skip to content

Commit 8e73f6c

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 b7fd773 commit 8e73f6c

File tree

9 files changed

+129
-208
lines changed

9 files changed

+129
-208
lines changed

ext/ffi/ffi.c

Lines changed: 78 additions & 109 deletions
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) {
@@ -3063,7 +3048,7 @@ ZEND_METHOD(FFI, cdef) /* {{{ */
30633048
}
30643049
}
30653050

3066-
ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3051+
ffi = (zend_ffi*)zend_ffi_scope_new(zend_ffi_scope_ce);
30673052
ffi->lib = handle;
30683053
ffi->symbols = FFI_G(symbols);
30693054
ffi->tags = FFI_G(tags);
@@ -3499,15 +3484,15 @@ static zend_ffi *zend_ffi_load(const char *filename, bool preload) /* {{{ */
34993484
}
35003485

35013486
if (EG(objects_store).object_buckets) {
3502-
ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3487+
ffi = (zend_ffi*)zend_ffi_scope_new(zend_ffi_scope_ce);
35033488
} else {
35043489
ffi = ecalloc(1, sizeof(zend_ffi));
35053490
}
35063491
ffi->symbols = scope->symbols;
35073492
ffi->tags = scope->tags;
35083493
ffi->persistent = 1;
35093494
} else {
3510-
ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3495+
ffi = (zend_ffi*)zend_ffi_scope_new(zend_ffi_scope_ce);
35113496
ffi->lib = handle;
35123497
ffi->symbols = FFI_G(symbols);
35133498
ffi->tags = FFI_G(tags);
@@ -3580,7 +3565,7 @@ ZEND_METHOD(FFI, scope) /* {{{ */
35803565
RETURN_THROWS();
35813566
}
35823567

3583-
ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3568+
ffi = (zend_ffi*)zend_ffi_scope_new(zend_ffi_scope_ce);
35843569

35853570
ffi->symbols = scope->symbols;
35863571
ffi->tags = scope->tags;
@@ -3759,7 +3744,7 @@ static void zend_ffi_tags_cleanup(zend_ffi_dcl *dcl) /* {{{ */
37593744
}
37603745
/* }}} */
37613746

3762-
ZEND_METHOD(FFI, new) /* {{{ */
3747+
static void _zend_ffi_new(INTERNAL_FUNCTION_PARAMETERS, bool is_static_call) /* {{{ */
37633748
{
37643749
zend_string *type_def = NULL;
37653750
zend_object *type_obj = NULL;
@@ -3769,7 +3754,6 @@ ZEND_METHOD(FFI, new) /* {{{ */
37693754
bool owned = 1;
37703755
bool persistent = 0;
37713756
bool is_const = 0;
3772-
bool is_static_call = Z_TYPE(EX(This)) != IS_OBJECT;
37733757
zend_ffi_flags flags = ZEND_FFI_FLAG_OWNED;
37743758

37753759
ZEND_FFI_VALIDATE_API_RESTRICTION();
@@ -3780,13 +3764,6 @@ ZEND_METHOD(FFI, new) /* {{{ */
37803764
Z_PARAM_BOOL(persistent)
37813765
ZEND_PARSE_PARAMETERS_END();
37823766

3783-
if (is_static_call) {
3784-
zend_error(E_DEPRECATED, "Calling FFI::new() statically is deprecated");
3785-
if (EG(exception)) {
3786-
RETURN_THROWS();
3787-
}
3788-
}
3789-
37903767
if (!owned) {
37913768
flags &= ~ZEND_FFI_FLAG_OWNED;
37923769
}
@@ -3884,6 +3861,18 @@ ZEND_METHOD(FFI, new) /* {{{ */
38843861
}
38853862
/* }}} */
38863863

3864+
ZEND_METHOD(FFI, new) /* {{{ */
3865+
{
3866+
_zend_ffi_new(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
3867+
}
3868+
/* }}} */
3869+
3870+
ZEND_METHOD(FFI_Scope, new) /* {{{ */
3871+
{
3872+
_zend_ffi_new(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
3873+
}
3874+
/* }}} */
3875+
38873876
ZEND_METHOD(FFI, free) /* {{{ */
38883877
{
38893878
zval *zv;
@@ -3918,14 +3907,13 @@ ZEND_METHOD(FFI, free) /* {{{ */
39183907
}
39193908
/* }}} */
39203909

3921-
ZEND_METHOD(FFI, cast) /* {{{ */
3910+
static void _zend_ffi_cast(INTERNAL_FUNCTION_PARAMETERS, bool is_static_call) /* {{{ */
39223911
{
39233912
zend_string *type_def = NULL;
39243913
zend_object *ztype = NULL;
39253914
zend_ffi_type *old_type, *type, *type_ptr;
39263915
zend_ffi_cdata *old_cdata, *cdata;
39273916
bool is_const = 0;
3928-
bool is_static_call = Z_TYPE(EX(This)) != IS_OBJECT;
39293917
zval *zv, *arg;
39303918
void *ptr;
39313919

@@ -3935,13 +3923,6 @@ ZEND_METHOD(FFI, cast) /* {{{ */
39353923
Z_PARAM_ZVAL(zv)
39363924
ZEND_PARSE_PARAMETERS_END();
39373925

3938-
if (is_static_call) {
3939-
zend_error(E_DEPRECATED, "Calling FFI::cast() statically is deprecated");
3940-
if (EG(exception)) {
3941-
RETURN_THROWS();
3942-
}
3943-
}
3944-
39453926
arg = zv;
39463927
ZVAL_DEREF(zv);
39473928

@@ -4101,25 +4082,29 @@ ZEND_METHOD(FFI, cast) /* {{{ */
41014082
}
41024083
/* }}} */
41034084

4104-
ZEND_METHOD(FFI, type) /* {{{ */
4085+
ZEND_METHOD(FFI, cast) /* {{{ */
4086+
{
4087+
_zend_ffi_cast(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
4088+
}
4089+
/* }}} */
4090+
4091+
ZEND_METHOD(FFI_Scope, cast) /* {{{ */
4092+
{
4093+
_zend_ffi_cast(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
4094+
}
4095+
/* }}} */
4096+
4097+
static void _zend_ffi_type(INTERNAL_FUNCTION_PARAMETERS, bool is_static_call) /* {{{ */
41054098
{
41064099
zend_ffi_ctype *ctype;
41074100
zend_ffi_dcl dcl = ZEND_FFI_ATTR_INIT;
41084101
zend_string *type_def;
4109-
bool is_static_call = Z_TYPE(EX(This)) != IS_OBJECT;
41104102

41114103
ZEND_FFI_VALIDATE_API_RESTRICTION();
41124104
ZEND_PARSE_PARAMETERS_START(1, 1)
41134105
Z_PARAM_STR(type_def);
41144106
ZEND_PARSE_PARAMETERS_END();
41154107

4116-
if (is_static_call) {
4117-
zend_error(E_DEPRECATED, "Calling FFI::type() statically is deprecated");
4118-
if (EG(exception)) {
4119-
RETURN_THROWS();
4120-
}
4121-
}
4122-
41234108
if (!is_static_call) {
41244109
zend_ffi *ffi = (zend_ffi*)Z_OBJ(EX(This));
41254110
FFI_G(symbols) = ffi->symbols;
@@ -4166,6 +4151,18 @@ ZEND_METHOD(FFI, type) /* {{{ */
41664151
}
41674152
/* }}} */
41684153

4154+
ZEND_METHOD(FFI, type) /* {{{ */
4155+
{
4156+
_zend_ffi_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
4157+
}
4158+
/* }}} */
4159+
4160+
ZEND_METHOD(FFI_Scope, type) /* {{{ */
4161+
{
4162+
_zend_ffi_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
4163+
}
4164+
/* }}} */
4165+
41694166
ZEND_METHOD(FFI, typeof) /* {{{ */
41704167
{
41714168
zval *zv, *arg;
@@ -5386,30 +5383,6 @@ static zend_result zend_ffi_preload(char *preload) /* {{{ */
53865383
}
53875384
/* }}} */
53885385

5389-
/* The startup code for observers adds a temporary to each function for internal use.
5390-
* The "new", "cast", and "type" functions in FFI are both static and non-static.
5391-
* Only the static versions are in the function table and the non-static versions are not.
5392-
* This means the non-static versions will be skipped by the observers startup code.
5393-
* This function fixes that by incrementing the temporary count for the non-static versions.
5394-
*/
5395-
static zend_result (*prev_zend_post_startup_cb)(void);
5396-
static zend_result ffi_fixup_temporaries(void) {
5397-
if (ZEND_OBSERVER_ENABLED) {
5398-
++zend_ffi_new_fn.T;
5399-
++zend_ffi_cast_fn.T;
5400-
++zend_ffi_type_fn.T;
5401-
}
5402-
#ifndef ZTS
5403-
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);
5404-
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);
5405-
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);
5406-
#endif
5407-
if (prev_zend_post_startup_cb) {
5408-
return prev_zend_post_startup_cb();
5409-
}
5410-
return SUCCESS;
5411-
}
5412-
54135386
/* {{{ ZEND_MINIT_FUNCTION */
54145387
ZEND_MINIT_FUNCTION(ffi)
54155388
{
@@ -5422,39 +5395,35 @@ ZEND_MINIT_FUNCTION(ffi)
54225395
zend_ffi_parser_exception_ce = register_class_FFI_ParserException(zend_ffi_exception_ce);
54235396

54245397
zend_ffi_ce = register_class_FFI();
5425-
zend_ffi_ce->create_object = zend_ffi_new;
54265398
zend_ffi_ce->default_object_handlers = &zend_ffi_handlers;
54275399

5428-
memcpy(&zend_ffi_new_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "new", sizeof("new")-1), sizeof(zend_internal_function));
5429-
zend_ffi_new_fn.fn_flags &= ~ZEND_ACC_STATIC;
5430-
memcpy(&zend_ffi_cast_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "cast", sizeof("cast")-1), sizeof(zend_internal_function));
5431-
zend_ffi_cast_fn.fn_flags &= ~ZEND_ACC_STATIC;
5432-
memcpy(&zend_ffi_type_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "type", sizeof("type")-1), sizeof(zend_internal_function));
5433-
zend_ffi_type_fn.fn_flags &= ~ZEND_ACC_STATIC;
5434-
5435-
prev_zend_post_startup_cb = zend_post_startup_cb;
5436-
zend_post_startup_cb = ffi_fixup_temporaries;
5400+
zend_ffi_scope_ce = register_class_FFI_Scope();
5401+
zend_ffi_scope_ce->create_object = zend_ffi_scope_new;
5402+
zend_ffi_scope_ce->default_object_handlers = &zend_ffi_scope_handlers;
54375403

54385404
memcpy(&zend_ffi_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
54395405
zend_ffi_handlers.get_constructor = zend_fake_get_constructor;
5440-
zend_ffi_handlers.free_obj = zend_ffi_free_obj;
5441-
zend_ffi_handlers.clone_obj = NULL;
5442-
zend_ffi_handlers.read_property = zend_ffi_read_var;
5443-
zend_ffi_handlers.write_property = zend_ffi_write_var;
5444-
zend_ffi_handlers.read_dimension = zend_fake_read_dimension;
5445-
zend_ffi_handlers.write_dimension = zend_fake_write_dimension;
5446-
zend_ffi_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5447-
zend_ffi_handlers.has_property = zend_fake_has_property;
5448-
zend_ffi_handlers.unset_property = zend_fake_unset_property;
5449-
zend_ffi_handlers.has_dimension = zend_fake_has_dimension;
5450-
zend_ffi_handlers.unset_dimension = zend_fake_unset_dimension;
5451-
zend_ffi_handlers.get_method = zend_ffi_get_func;
5452-
zend_ffi_handlers.compare = zend_fake_compare_objects;
5453-
zend_ffi_handlers.cast_object = zend_fake_cast_object;
5454-
zend_ffi_handlers.get_debug_info = NULL;
5455-
zend_ffi_handlers.get_closure = NULL;
5456-
zend_ffi_handlers.get_properties = zend_fake_get_properties;
5457-
zend_ffi_handlers.get_gc = zend_fake_get_gc;
5406+
5407+
memcpy(&zend_ffi_scope_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5408+
zend_ffi_scope_handlers.get_constructor = zend_fake_get_constructor;
5409+
zend_ffi_scope_handlers.free_obj = zend_ffi_scope_free_obj;
5410+
zend_ffi_scope_handlers.clone_obj = NULL;
5411+
zend_ffi_scope_handlers.read_property = zend_ffi_scope_read_var;
5412+
zend_ffi_scope_handlers.write_property = zend_ffi_scope_write_var;
5413+
zend_ffi_scope_handlers.read_dimension = zend_fake_read_dimension;
5414+
zend_ffi_scope_handlers.write_dimension = zend_fake_write_dimension;
5415+
zend_ffi_scope_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5416+
zend_ffi_scope_handlers.has_property = zend_fake_has_property;
5417+
zend_ffi_scope_handlers.unset_property = zend_fake_unset_property;
5418+
zend_ffi_scope_handlers.has_dimension = zend_fake_has_dimension;
5419+
zend_ffi_scope_handlers.unset_dimension = zend_fake_unset_dimension;
5420+
zend_ffi_scope_handlers.get_method = zend_ffi_scope_get_func;
5421+
zend_ffi_scope_handlers.compare = zend_fake_compare_objects;
5422+
zend_ffi_scope_handlers.cast_object = zend_fake_cast_object;
5423+
zend_ffi_scope_handlers.get_debug_info = NULL;
5424+
zend_ffi_scope_handlers.get_closure = NULL;
5425+
zend_ffi_scope_handlers.get_properties = zend_fake_get_properties;
5426+
zend_ffi_scope_handlers.get_gc = zend_fake_get_gc;
54585427

54595428
zend_ffi_cdata_ce = register_class_FFI_CData();
54605429
zend_ffi_cdata_ce->create_object = zend_ffi_cdata_new;

ext/ffi/ffi.stub.php

Lines changed: 16 additions & 3 deletions
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)