Skip to content
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

Invalid error for session_set_save_handler() #737

Closed
ADmad opened this issue Oct 25, 2019 · 21 comments
Closed

Invalid error for session_set_save_handler() #737

ADmad opened this issue Oct 25, 2019 · 21 comments
Milestone

Comments

@ADmad
Copy link

ADmad commented Oct 25, 2019

Describe the bug
session_set_save_handler() has two prototypes. One requires only 2 arguments. Using that prototype (with correct argument types) intelephense incorrectly reports that Expected 6 arguments. Found 2.

To Reproduce
session_set_save_handler($handlerObject, false)

Expected behavior
No error to be reported.

@KapitanOczywisty
Copy link
Contributor

KapitanOczywisty commented Oct 25, 2019

https://github.com/JetBrains/phpstorm-stubs/blob/master/session/session.php#L220-L282

Good catch, Side effect of fixing that could be support for "Method Overloading".

For contrast number_format cannot be called with 3 parameters, but this isn't even mentioned in stubs
https://github.com/JetBrains/phpstorm-stubs/blob/master/standard/standard_3.php#L693-L708

@ADmad
Copy link
Author

ADmad commented Oct 25, 2019

The callmap used by psalm is one of the most up to date in my experience https://raw.githubusercontent.com/vimeo/psalm/master/src/Psalm/Internal/CallMap.php

@KapitanOczywisty
Copy link
Contributor

You may be right, it's done using reflection in contrary to user-created phpstorm-stubs, but also don't need to be commented (phpdoc). Intelephense uses phpstorm-stubs because of comments.

@ADmad
Copy link
Author

ADmad commented Oct 25, 2019

it's done using reflection

Maybe to begin with but it's now maintained by hand, I have personally submitted manual updates to that file.

@KapitanOczywisty
Copy link
Contributor

If I'm not mistaken phpstorm stubs started from php.net docs years ago. User changes are unavoidable in both, but scale is a bit different.

@ADmad
Copy link
Author

ADmad commented Oct 25, 2019

Yeah, psalm doesn't need to show docblock descriptions like intelephense, it only needs the type info.

@KapitanOczywisty
Copy link
Contributor

KapitanOczywisty commented Dec 7, 2019

I've generated list of functions w/ multiple variants, using file from @ADmad comment. I found 113 functions with 234 variants.

abs ( int $number ) : int {}
abs ( float $number ) : float {}
abs ( numeric $number ) : numeric {}
apc_add ( string $key, mixed $var, [ int $ttl ] ) : bool {}
apc_add ( array $values, [ $unused, int $ttl ] ) : array {}
apc_exists ( string $keys ) : bool {}
apc_exists ( string[] $keys ) : array {}
apc_fetch ( string $key, [ bool &$w_success ] ) : mixed|false {}
apc_fetch ( string[] $key, [ bool &$w_success ] ) : array|false {}
apc_store ( string $key, $var, [ int $ttl ] ) : bool {}
apc_store ( array $values, [ $unused, int $ttl ] ) : array {}
apcu_add ( string $key, $var, [ int $ttl ] ) : bool {}
apcu_add ( array<string,mixed> $values, [ $unused, int $ttl ] ) : array<string,int> {}
apcu_exists ( string $keys ) : bool {}
apcu_exists ( string[] $keys ) : array {}
apcu_fetch ( string $key, [ bool &$w_success ] ) : mixed|false {}
apcu_fetch ( string[] $key, [ bool &$w_success ] ) : array|false {}
apcu_store ( string $key, [ $var, int $ttl ] ) : bool {}
apcu_store ( array $values, [ $unused, int $ttl ] ) : array {}
array_diff_uassoc ( array $arr1, array $arr2, callable(mixed,mixed):int $data_comp_func ) : array {}
array_diff_uassoc ( array $arr1, array $arr2, array $arr3, array|callable(mixed,mixed):int $arg4, [ array|callable(mixed,mixed):int ...$rest ] ) : array {}
array_diff_ukey ( array $arr1, array $arr2, callable(mixed,mixed):int $key_comp_func ) : array {}
array_diff_ukey ( array $arr1, array $arr2, array $arr3, array|callable(mixed,mixed):int $arg4, [ array|callable(mixed,mixed):int ...$rest ] ) : array {}
array_intersect_uassoc ( array $arr1, array $arr2, callable(mixed,mixed):int $key_compare_func ) : array {}
array_intersect_uassoc ( array $arr1, array $arr2, array $arr3, array|callable(mixed,mixed):int $arg4, array|callable(mixed,mixed):int ...$rest ) : array {}
array_intersect_ukey ( array $arr1, array $arr2, callable(mixed,mixed):int $key_compare_func ) : array {}
array_intersect_ukey ( array $arr1, array $arr2, array $arr3, array|callable(mixed,mixed):int $arg4, array|callable(mixed,mixed):int ...$rest ) : array {}
array_rand ( array $input, int $num_req ) : int|string|array<int,int>|array<int,string> {}
array_rand ( array $input ) : int|string {}
array_udiff ( array $arr1, array $arr2, callable(mixed,mixed):int $data_comp_func ) : array {}
array_udiff ( array $arr1, array $arr2, array $arr3, array|callable(mixed,mixed):int $arg4, [ array|callable(mixed,mixed):int ...$rest ] ) : array {}
array_udiff_assoc ( array $arr1, array $arr2, callable(mixed,mixed):int $key_comp_func ) : array {}
array_udiff_assoc ( array $arr1, array $arr2, array $arr3, array|callable(mixed,mixed):int $arg4, [ array|callable(mixed,mixed):int ...$rest ] ) : array {}
array_udiff_uassoc ( array $arr1, array $arr2, callable(mixed,mixed):int $data_comp_func, callable(mixed,mixed):int $key_comp_func ) : array {}
array_udiff_uassoc ( array $arr1, array $arr2, array $arr3, array|callable(mixed,mixed):int $arg4, array|callable(mixed,mixed):int $arg5, [ array|callable(mixed,mixed):int ...$rest ] ) : array {}
array_uintersect ( array $arr1, array $arr2, callable(mixed,mixed):int $data_compare_func ) : array {}
array_uintersect ( array $arr1, array $arr2, array $arr3, array|callable(mixed,mixed):int $arg4, [ array|callable(mixed,mixed):int ...$rest ] ) : array {}
array_uintersect_assoc ( array $arr1, array $arr2, callable(mixed,mixed):int $data_compare_func ) : array {}
array_uintersect_assoc ( array $arr1, array $arr2, array $arr3, array|callable $arg4, [ array|callable(mixed,mixed):int ...$rest ] ) : array {}
array_uintersect_uassoc ( array $arr1, array $arr2, callable(mixed,mixed):int $data_compare_func, callable(mixed,mixed):int $key_compare_func ) : array {}
array_uintersect_uassoc ( array $arr1, array $arr2, array $arr3, array|callable(mixed,mixed):int $arg4, array|callable(mixed,mixed):int $arg5, [ array|callable(mixed,mixed):int ...$rest ] ) : array {}
DatePeriod::__construct ( DateTimeInterface $start, DateInterval $interval, int $recur, [ int $options ] ) : void {}
DatePeriod::__construct ( DateTimeInterface $start, DateInterval $interval, DateTimeInterface $end, [ int $options ] ) : void {}
DatePeriod::__construct ( string $iso, [ int $options ] ) : void {}
dba_fetch ( string $key, int $skip, resource $handle ) : string|false {}
dba_fetch ( string $key, resource $handle ) : string|false {}
fscanf ( resource $stream, string $format ) : array {}
fscanf ( resource $stream, string $format, [ string|int|float &...$w_vars ] ) : int {}
getenv ( string $varname, [ bool $local_only ] ) : string|false {}
getenv ( ) : array<string,string> {}
gettimeofday ( ) : array {}
gettimeofday ( [ true $get_as_float ] ) : float {}
hrtime ( [ false $get_as_number ] ) : array{0:int,1:int}|false {}
hrtime ( [ true $get_as_number ] ) : int|float|false {}
ibase_blob_echo ( $link_identifier, string $blob_id ) : bool {}
ibase_blob_echo ( string $blob_id ) : bool {}
ibase_blob_info ( resource $link_identifier, string $blob_id ) : array {}
ibase_blob_info ( string $blob_id ) : array {}
ibase_blob_open ( resource $link_identifier, string $blob_id ) : resource {}
ibase_blob_open ( string $blob_id ) : resource {}
ibase_set_event_handler ( $link_identifier, callable $callback, [ string $event, ...$args ] ) : resource {}
ibase_set_event_handler ( callable $callback, string $event, ...$args ) : resource {}
ibase_wait_event ( $link_identifier, [ string $event, ...$args ] ) : string {}
ibase_wait_event ( string $event, ...$args ) : string {}
implode ( string $glue, array $pieces ) : string {}
implode ( array $pieces ) : string {}
intlcal_set ( IntlCalendar $cal, int $field, int $value ) : bool {}
intlcal_set ( IntlCalendar $cal, int $year, int $month, [ int $dayOfMonth, int $hour, int $minute, int $second ] ) : bool {}
IntlCalendar::set ( int $field, int $value ) : bool {}
IntlCalendar::set ( int $year, int $month, [ int $dayOfMonth, int $hour, int $minute, int $second ] ) : bool {}
IntlGregorianCalendar::set ( int $field, int $value ) : bool {}
IntlGregorianCalendar::set ( int $year, int $month, [ int $dayOfMonth, int $hour, int $minute, int $second ] ) : bool {}
join ( string $glue, array $pieces ) : string {}
join ( array $pieces ) : string {}
levenshtein ( string $str1, string $str2 ) : int {}
levenshtein ( string $str1, string $str2, int $cost_ins, int $cost_rep, int $cost_del ) : int {}
max ( array $arg1 ) : mixed {}
max ( $arg1, $arg2, [ ...$args ] ) : mixed {}
maxdb_stmt::bind_param ( $stmt, string $types, &...$rw_var ) : bool {}
maxdb_stmt::bind_param ( $stmt, string $types, array &$rw_var ) : bool {}
min ( array $arg1 ) : mixed {}
min ( $arg1, $arg2, [ ...$args ] ) : mixed {}
MongoCollection::aggregate ( array $op, [ array $op, array ...$args ] ) : array {}
MongoCollection::aggregate ( array $pipeline, [ array $options ] ) : array {}
mt_rand ( int $min, int $max ) : int {}
mt_rand ( ) : int {}
newrelic_notice_error ( string $message, [ Exception|Throwable $exception ] ) : void {}
newrelic_notice_error ( string $unused_1, string $message, string $unused_2, int $unused_3, [ $unused_4 ] ) : void {}
number_format ( float|int $number, [ int $num_decimal_places ] ) : string {}
number_format ( float|int $number, int $num_decimal_places, string $dec_separator, string $thousands_separator ) : string {}
PDO::query ( string $sql ) : PDOStatement|false {}
PDO::query ( string $sql, int $fetch_column, int $colno ) : PDOStatement|false {}
PDO::query ( string $sql, int $fetch_class, string $classname, array $ctorargs ) : PDOStatement|false {}
PDO::query ( string $sql, int $fetch_into, object $object ) : PDOStatement|false {}
PDOStatement::setFetchMode ( int $mode ) : bool {}
PDOStatement::setFetchMode ( int $fetch_column, int $colno ) : bool {}
PDOStatement::setFetchMode ( int $fetch_class, string $classname, array $ctorargs ) : bool {}
PDOStatement::setFetchMode ( int $fetch_into, object $object ) : bool {}
pg_escape_bytea ( resource $connection, string $data ) : string {}
pg_escape_bytea ( string $data ) : string {}
pg_escape_identifier ( resource $connection, string $data ) : string {}
pg_escape_identifier ( string $data ) : string {}
pg_escape_literal ( resource $connection, string $data ) : string {}
pg_escape_literal ( string $data ) : string {}
pg_escape_string ( resource $connection, string $data ) : string {}
pg_escape_string ( string $data ) : string {}
pg_execute ( resource $connection, string $stmtname, array $params ) : resource|false {}
pg_execute ( string $stmtname, array $params ) : resource|false {}
pg_fetch_object ( resource $result, [ ?int $row, int $result_type ] ) : object {}
pg_fetch_object ( resource $result, [ ?int $row, string $class_name, array $ctor_params ] ) : object {}
pg_fetch_result ( resource $result, string|int $field_name ) : string {}
pg_fetch_result ( resource $result, ?int $row, string|int $field_name ) : string {}
pg_field_is_null ( resource $result, string|int $field_name_or_number ) : int {}
pg_field_is_null ( resource $result, int $row, string|int $field_name_or_number ) : int {}
pg_field_prtlen ( resource $result, $field_name_or_number ) : int|false {}
pg_field_prtlen ( resource $result, int $row, string|int $field_name_or_number ) : int {}
pg_lo_export ( resource $connection, int $oid, string $filename ) : bool {}
pg_lo_export ( int $oid, string $pathname ) : bool {}
pg_lo_import ( resource $connection, string $pathname, $oid ) : int {}
pg_lo_import ( string $pathname, $oid ) : int {}
pg_parameter_status ( resource $connection, string $param_name ) : string|false {}
pg_parameter_status ( string $param_name ) : string|false {}
pg_prepare ( resource $connection, string $stmtname, string $query ) : resource|false {}
pg_prepare ( string $stmtname, string $query ) : resource|false {}
pg_put_line ( resource $connection, string $data ) : bool {}
pg_put_line ( string $data ) : bool {}
pg_query ( resource $connection, string $query ) : resource|false {}
pg_query ( string $query ) : resource|false {}
pg_query_params ( resource $connection, string $query, array $params ) : resource|false {}
pg_query_params ( string $query, array $params ) : resource|false {}
pg_set_client_encoding ( resource $connection, string $encoding ) : int {}
pg_set_client_encoding ( string $encoding ) : int {}
pg_set_error_verbosity ( resource $connection, int $verbosity ) : int {}
pg_set_error_verbosity ( int $verbosity ) : int {}
pg_tty ( [ resource $connection ] ) : string {}
pg_tty ( ) : string {}
pg_untrace ( [ resource $connection ] ) : bool {}
pg_untrace ( ) : bool {}
preg_match ( string $pattern, string $subject, [ string[] &$w_subpatterns, 0| $flags, int $offset ] ) : int|false {}
preg_match ( string $pattern, string $subject, [ array &$w_subpatterns, int $flags, int $offset ] ) : int|false {}
preg_replace_callback ( string|array $regex, callable(array<int, string>):string $callback, string $subject, [ int $limit, int &$w_count ] ) : string|null {}
preg_replace_callback ( string|array $regex, callable(array<int, string>):string $callback, string[] $subject, [ int $limit, int &$w_count ] ) : string[]|null {}
preg_split ( string $pattern, string $subject, ?int $limit, [ null $flags ] ) : array<int,string>|false {}
preg_split ( string $pattern, string $subject, [ ?int $limit, int $flags ] ) : array<int,string>|array[]|false {}
print_r ( mixed $var ) : string {}
print_r ( mixed $var, [ bool $return ] ) : true {}
rand ( int $min, int $max ) : int {}
rand ( ) : int {}
Redis::del ( string $key, string ...$args ) : int {}
Redis::del ( string[] $key ) : int {}
Redis::delete ( string $key, string ...$args ) : int {}
Redis::delete ( string[] $key ) : int {}
Redis::exists ( string $key ) : int {}
Redis::exists ( string[] $key ) : int {}
Redis::set ( string $key, string $value, [ array $options ] ) : bool {}
Redis::set ( string $key, string $value, [ int $timeout ] ) : bool {}
Redis::slave ( string $host, int $port ) : bool {}
Redis::slave ( string $host, int $port ) : bool {}
Redis::unlink ( string $key, string ...$args ) : int {}
Redis::unlink ( string[] $key ) : int {}
RedisArray::delete ( string $key, string ...$args ) : bool {}
RedisArray::delete ( string[] $key ) : bool {}
ReflectionMethod::__construct ( string|object $class, string $name ) : void {}
ReflectionMethod::__construct ( string $class_method ) : void {}
ReflectionProperty::setValue ( object $object, $value ) : void {}
ReflectionProperty::setValue ( $value ) : void {}
runkit_function_add ( string $funcname, string $arglist, string $code, [ ?string $doccomment ] ) : bool {}
runkit_function_add ( string $funcname, Closure $closure, [ ?string $doccomment ] ) : bool {}
runkit_function_redefine ( string $funcname, string $arglist, string $code, [ ?string $doccomment ] ) : bool {}
runkit_function_redefine ( string $funcname, Closure $closure, [ ?string $doccomment ] ) : bool {}
runkit_method_add ( string $classname, string $methodname, string $args, string $code, [ int $flags, ?string $doccomment ] ) : bool {}
runkit_method_add ( string $classname, string $methodname, Closure $closure, [ int $flags, ?string $doccomment ] ) : bool {}
runkit_method_redefine ( string $classname, string $methodname, string $args, string $code, [ int $flags, ?string $doccomment ] ) : bool {}
runkit_method_redefine ( string $classname, string $methodname, Closure $closure, [ int $flags, ?string $doccomment ] ) : bool {}
session_set_cookie_params ( int $lifetime, [ string $path, ?string $domain, bool $secure, bool $httponly ] ) : bool {}
session_set_cookie_params ( array{lifetime?:int,path?:string,domain?:?string,secure?:bool,httponly?:bool} $options ) : bool {}
session_set_save_handler ( callable(string,string):bool $open, callable():bool $close, callable(string):string $read, callable(string,string):bool $write, callable(string):bool $destroy, callable(string):bool $gc, [ callable():string $create_sid, callable(string):bool $validate_sid, callable(string):bool $update_timestamp ] ) : bool {}
session_set_save_handler ( SessionHandlerInterface $sessionhandler, [ bool $register_shutdown ] ) : bool {}
setcookie ( string $name, [ string $value, int $expires, string $path, string $domain, bool $secure, bool $httponly ] ) : bool {}
setcookie ( string $name, [ string $value, array $options ] ) : bool {}
setlocale ( int $category, string|0|null $locale, [ string ...$args ] ) : string|false {}
setlocale ( int $category, ?array $locale ) : string|false {}
SimpleXMLElement::asXML ( string $filename ) : bool {}
SimpleXMLElement::asXML ( ) : string|false {}
stream_context_set_option ( $context, string $wrappername, string $optionname, $value ) : bool {}
stream_context_set_option ( $context, array $options ) : bool {}
strtok ( string $str, string $token ) : string|false {}
strtok ( string $token ) : string|false {}
strtr ( string $str, string $from, string $to ) : string {}
strtr ( string $str, array $replace_pairs ) : string {}
SWFShape::addFill ( int $red, int $green, int $blue, [ int $alpha, swfbitmap $bitmap, int $flags, swfgradient $gradient ] ) : SWFFill {}
SWFShape::addFill ( SWFBitmap $bitmap, [ int $flags ] ) : SWFFill {}
SWFShape::addFill ( SWFGradient $gradient, [ int $flags ] ) : SWFFill {}
uopz_backup ( string $class, string $function ) : void {}
uopz_backup ( string $function ) : void {}
uopz_copy ( string $class, string $function ) : Closure {}
uopz_copy ( string $function ) : Closure {}
uopz_delete ( string $class, string $function ) : void {}
uopz_delete ( string $function ) : void {}
uopz_flags ( string $class, string $function, int $flags ) : int {}
uopz_flags ( string $function, int $flags ) : int {}
uopz_function ( string $class, string $function, Closure $handler, [ int $modifiers ] ) : void {}
uopz_function ( string $function, Closure $handler, [ int $modifiers ] ) : void {}
uopz_get_hook ( string $class, string $function ) : ?Closure {}
uopz_get_hook ( string $function ) : ?Closure {}
uopz_redefine ( string $class, string $constant, mixed $value ) : bool {}
uopz_redefine ( string $constant, mixed $value ) : bool {}
uopz_rename ( string $class, string $function, string $rename ) : void {}
uopz_rename ( string $function, string $rename ) : void {}
uopz_restore ( string $class, string $function ) : void {}
uopz_restore ( string $function ) : void {}
uopz_set_hook ( string $class, string $function, Closure $hook ) : bool {}
uopz_set_hook ( string $function, Closure $hook ) : bool {}
uopz_set_return ( string $function, mixed $value, [ string $class, bool $execute ] ) : bool {}
uopz_set_return ( string $function, mixed $value, [ bool $execute ] ) : bool {}
uopz_undefine ( string $class, string $constant ) : bool {}
uopz_undefine ( string $constant ) : bool {}
uopz_unset_hook ( string $class, string $function ) : bool {}
uopz_unset_hook ( string $function ) : bool {}
uopz_unset_return ( string $function, [ string $class ] ) : bool {}
uopz_unset_return ( string $function ) : bool {}
version_compare ( string $ver1, string $ver2, '\x3c'|'lt'|'\x3c='|'le'|'\x3e'|'gt'|'\x3e='|'ge'|'=='|'='|'eq'|'!='|'\x3c\x3e'|'ne' $oper ) : bool {}
version_compare ( string $ver1, string $ver2, [ $oper ] ) : int {}
wincache_ucache_add ( string $key, mixed $value, [ int $ttl ] ) : bool {}
wincache_ucache_add ( array $values, [ $unused, int $ttl ] ) : bool {}
wincache_ucache_set ( $key, $value, [ int $ttl ] ) : bool {}
wincache_ucache_set ( array $values, [ $unused, int $ttl ] ) : bool {}
XSLTProcessor::setParameter ( string $namespace, string $name, string $value ) : bool {}
XSLTProcessor::setParameter ( string $namespace, array $options ) : bool {}
Yaf_Controller_Abstract::forward ( string $action, [ array $parameters ] ) : void {}
Yaf_Controller_Abstract::forward ( string $controller, string $action, [ array $parameters ] ) : void {}
Yaf_Controller_Abstract::forward ( string $module, string $controller, string $action, [ array $parameters ] ) : void {}
ZMQSocket::send ( array $message, [ int $mode ] ) : ZMQSocket {}
ZMQSocket::send ( string $message, [ int $mode ] ) : ZMQSocket {}
// Functions: 113 / Variants: 234

@bmewburn
Copy link
Owner

fixed in 1.3.3

@KaduAmaral
Copy link

Not fixed properly...

image

@KapitanOczywisty
Copy link
Contributor

@KaduAmaral What error you have? What type are $sql and $params? Are you using 1.3.3 version?

@KaduAmaral
Copy link

KaduAmaral commented Dec 10, 2019

Same error of issue #859, Invalid number of arguments. In case my $sql is a string, and my $params is an array or null.

My version is 1.3.3.

image

@KapitanOczywisty
Copy link
Contributor

After last updates it's not throwing errors even for this strtr('', '');, maybe it needs reindexing?

@KaduAmaral
Copy link

I've tried uninstall/reinstall, but is still showing the message. How can I reindex?

@KapitanOczywisty
Copy link
Contributor

When any php file is open: Command palette (Ctrl+Shift+P) -> Intelephense: Index workspace.

@ADmad
Copy link
Author

ADmad commented Dec 11, 2019

I can confirm that error is no longer generated with usage like session_set_save_handler($handlerObject, false) but now it doesn't show error even if I have usage like session_set_save_handler('', '').

@KapitanOczywisty
Copy link
Contributor

@ADmad This is because #788 you can complain show your support in #830

@ADmad
Copy link
Author

ADmad commented Dec 11, 2019

@KapitanOczywisty I don't see how that relates to my issue. My call to session_set_save_handler() doesn't involve any use of arrays.

@KapitanOczywisty
Copy link
Contributor

KapitanOczywisty commented Dec 11, 2019

tl;dr there were cases when types were incompatible when they wouldn't irl and author made type checking more relaxed. It's not related to function overloading itself.

@KaduAmaral
Copy link

KaduAmaral commented Dec 11, 2019

When any php file is open: Command palette (Ctrl+Shift+P) -> Intelephense: Index workspace.

After do this the message disappear. Thank you!

image


Your plugin is amazing, if you need help let me know.

@bmewburn
Copy link
Owner

bmewburn commented Dec 11, 2019

@ADmad I opened #869 as there appears to be another issue here when multiple function signatures are found

@ADmad
Copy link
Author

ADmad commented Dec 12, 2019

@bmewburn Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants