-
Notifications
You must be signed in to change notification settings - Fork 7.9k
FFI::CType reflection API #7217
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks reasonable to me, don't have anything to add in terms of implementation.
Just some bikeshedding on method names.
except for "getPointerType" -> "getPointerElementType"
I changes names according to your suggestion, except for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello, @dstogov! Thank you for this improvement! Looks awesome!
I have only small suggestions regarding better method names, which will be used better.
Also, want to avoid some specific methods for CType
that can be implemented better as children classes, eg CArrayType
, CStructureType
. But this can require some additional changes... @dstogov @nikic what do you think?
} | ||
/* }}} */ | ||
|
||
ZEND_METHOD(FFI_CType, getArrayElementType) /* {{{ */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about extraction of separate CArrayType
for this? It can make API stable and more logical, as there is no point in calling getArrayElementType
for simple scalar types - it will always throw an error, which can be example of LSP principle - we will have methods that won't work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, it's possible to introduce and instantiate CArrayType instead of CType, but I don't like to do this in last minute and without RFC.
|
||
type = ZEND_FFI_TYPE(ctype->type); | ||
if (type->kind != ZEND_FFI_TYPE_ARRAY) { | ||
zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not an array"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This runtime check can be avoid by moving implementation into the separate CArrayType
} | ||
/* }}} */ | ||
|
||
ZEND_METHOD(FFI_CType, getPointerType) /* {{{ */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, we can have separate CPointerType, which will give us better visibility in PHP code.
} | ||
/* }}} */ | ||
|
||
ZEND_METHOD(FFI_CType, getFuncArgType) /* {{{ */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getFunctionArgumentType()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in my opinion, this longer name doesn't make things more clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PHP is already already using "Parameter" instead of "Argument" for reflection on types elsewhere.
Also, would omitting Func for something like getParameterType make more sense - nothing other than functions would have parameters.
zend_ffi_ctype *ret; | ||
|
||
ZEND_PARSE_PARAMETERS_START(1, 1) | ||
Z_PARAM_LONG(n) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
argumentIndex?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes sense, but not in this place but in stub, and probably $arg_index.
} | ||
|
||
if (!type->func.args) { | ||
zend_throw_error(zend_ffi_exception_ce, "Wrong argument number"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe state explicitly that "Function $name has not arguments".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May be this makes sense, however, we don't know the function name at this point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, then current one should be ok
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
zend_throw_error(zend_ffi_exception_ce, "Wrong argument number"); | |
zend_throw_error(zend_ffi_exception_ce, "Missing parameter offset #d of FFI function with %d parameter(s)", ...); |
Maybe something more along these lines with the argument count and offset being fetched, to speed up debugging? (my wording can be improved)
ext/ffi/ffi.stub.php
Outdated
public function getFuncABI(): int {} | ||
public function getFuncReturnType(): CType {} | ||
public function getFuncArgCount(): int {} | ||
public function getFuncArgType(int $n): CType {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public function getFuncArgType(int $n): CType {} | |
public function getFunctionArgumentType(int $argumentIndex): CType {} |
As I can see method names have been partially updated already. |
I agree that using subclasses would be cleaner in principle, but I'm also okay with the current approach. |
Ah, I probably picked up an LLVM-ism, where this is called "pointer element type" (or sometimes "pointee type"). I think just keeping |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM despite nits on naming - I think it'd be easier to remember this if names were consistent with Reflection APIs already in PHP such as https://www.php.net/manual/en/class.reflectionfunctionabstract.php
} | ||
/* }}} */ | ||
|
||
ZEND_METHOD(FFI_CType, getArrayLength) /* {{{ */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would implementing Countable and calling this Countable::count() make sense here (continuing to throw for non-arrays)? for ($i = 0; $i < count($ffiArray); $i++) {...}
Then again, that'd be a much larger change and that interface isn't in FFI\CData for 8.0
} | ||
/* }}} */ | ||
|
||
ZEND_METHOD(FFI_CType, getFuncReturnType) /* {{{ */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to use the same names that reflection already uses for these methods? https://www.php.net/manual/en/reflectionfunctionabstract.getreturntype.php E.g. getReturnType
} | ||
/* }}} */ | ||
|
||
ZEND_METHOD(FFI_CType, getFuncArgCount) /* {{{ */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://www.php.net/manual/en/reflectionfunctionabstract.getnumberofparameters.php
Alternately, getNumberOfParameters
} | ||
/* }}} */ | ||
|
||
ZEND_METHOD(FFI_CType, getFuncArgType) /* {{{ */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PHP is already already using "Parameter" instead of "Argument" for reflection on types elsewhere.
Also, would omitting Func for something like getParameterType make more sense - nothing other than functions would have parameters.
if (zend_parse_parameters_none() == FAILURE) { | ||
RETURN_THROWS(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (zend_parse_parameters_none() == FAILURE) { | |
RETURN_THROWS(); | |
} | |
ZEND_PARSE_PARAMETERS_NONE(); |
nit: Could be shortened here and elsewhere. Is there a reason for different parts of the codebase using different ways of writing this?
} | ||
|
||
if (!type->func.args) { | ||
zend_throw_error(zend_ffi_exception_ce, "Wrong argument number"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
zend_throw_error(zend_ffi_exception_ce, "Wrong argument number"); | |
zend_throw_error(zend_ffi_exception_ce, "Missing parameter offset #d of FFI function with %d parameter(s)", ...); |
Maybe something more along these lines with the argument count and offset being fetched, to speed up debugging? (my wording can be improved)
Elsewhere in php, Parameter is used to refer to the function declarations (AST_PARAM, ReflectionFunctionAbstract->getParameters(), etc.) Other languages use similar definitions, e.g. https://developer.mozilla.org/en-US/docs/Glossary/Parameter |
Merged via a2845e3 |
I understand that it is already merged, but won't $type = \FFI::type('uint8_t');
// #define HAVE_LONG_DOUBLE 1
var_dump($type->getKind()); // 4
// #define HAVE_LONG_DOUBLE 0
var_dump($type->getKind()); // 3 That is, we cannot be guided by these values with complete confidence. Maybe it makes sense to add a set of constants like? namespace FFI;
class CType
{
public const TYPE_KIND_VOID = // ZEND_FFI_TYPE_VOID;
public const TYPE_KIND_FLOAT = // ZEND_FFI_TYPE_FLOAT;
// etc...
} The same goes for other enams defined in ffi.c |
@SerafimArts These constants are already present: Line 5357 in e1f211f
|
@nikic Oh, then I'm sorry, I didn't notice |
No description provided.