1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-22 13:51:54 +01:00

Merge branch 'master' into cleaunup-unsupported-extentions-message

This commit is contained in:
Alies Lapatsin 2023-01-10 18:59:58 +01:00 committed by GitHub
commit e21e38d5ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 317 additions and 231 deletions

View File

@ -3699,7 +3699,7 @@ return [
'get_defined_functions' => ['array{internal: list<callable-string>, user: list<callable-string>}', 'exclude_disabled='=>'bool'],
'get_defined_vars' => ['array'],
'get_extension_funcs' => ['list<callable-string>|false', 'extension'=>'string'],
'get_headers' => ['array|false', 'url'=>'string', 'associative='=>'int', 'context='=>'resource'],
'get_headers' => ['array|false', 'url'=>'string', 'associative='=>'bool', 'context='=>'?resource'],
'get_html_translation_table' => ['array', 'table='=>'int', 'flags='=>'int', 'encoding='=>'string'],
'get_include_path' => ['string'],
'get_included_files' => ['list<string>'],

View File

@ -48,7 +48,7 @@ return [
],
'get_headers' => [
'old' => ['array|false', 'url'=>'string', 'associative='=>'int'],
'new' => ['array|false', 'url'=>'string', 'associative='=>'int', 'context='=>'resource'],
'new' => ['array|false', 'url'=>'string', 'associative='=>'int', 'context='=>'?resource'],
],
'getopt' => [
'old' => ['array<string,string|false|list<string|false>>|false', 'short_options'=>'string', 'long_options='=>'array'],

View File

@ -673,6 +673,10 @@ return [
'old' => ['list<string>|null', 'object_or_class'=>'mixed'],
'new' => ['list<string>', 'object_or_class'=>'object|class-string'],
],
'get_headers' => [
'old' => ['array|false', 'url'=>'string', 'associative='=>'int', 'context='=>'?resource'],
'new' => ['array|false', 'url'=>'string', 'associative='=>'bool', 'context='=>'?resource'],
],
'get_parent_class' => [
'old' => ['class-string|false', 'object_or_class='=>'mixed'],
'new' => ['class-string|false', 'object_or_class='=>'object|class-string'],

View File

@ -10,6 +10,7 @@ use Psalm\Internal\Analyzer\FunctionLikeAnalyzer;
use Psalm\Internal\Analyzer\Statements\Expression\AssertionFinder;
use Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier;
use Psalm\Internal\Analyzer\Statements\Expression\Fetch\ConstFetchAnalyzer;
use Psalm\Internal\Analyzer\Statements\Expression\IncludeAnalyzer;
use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer;
use Psalm\Internal\Analyzer\StatementsAnalyzer;
use Psalm\Internal\Codebase\VariableUseGraph;
@ -178,6 +179,22 @@ class NamedFunctionCallHandler
if ($var_id) {
$context->phantom_files[$var_id] = true;
return;
}
// literal string or (magic) const in file path
$codebase = $statements_analyzer->getCodebase();
$config = $codebase->config;
$path_to_file = IncludeAnalyzer::getPathTo(
$first_arg->value,
$statements_analyzer->node_data,
$statements_analyzer,
$statements_analyzer->getFileName(),
$config,
);
if ($path_to_file) {
$context->phantom_files[$path_to_file] = true;
}
return;

View File

@ -231,6 +231,15 @@ class IncludeAnalyzer
return true;
}
if (isset($context->phantom_files[$path_to_file])) {
return true;
}
$var_id = ExpressionIdentifier::getExtendedVarId($stmt->expr, null);
if ($var_id && isset($context->phantom_files[$var_id])) {
return true;
}
$source = $statements_analyzer->getSource();
IssueBuffer::maybeAdd(

View File

@ -592,11 +592,15 @@ class FunctionLikeNodeScanner
$var_comment_readonly = false;
$var_comment_allow_private_mutation = false;
if ($doc_comment) {
$template_types = ($this->existing_function_template_types ?: [])
+ ($classlike_storage->template_types ?: [])
;
$var_comments = CommentAnalyzer::getTypeFromComment(
$doc_comment,
$this->file_scanner,
$this->aliases,
$this->existing_function_template_types ?: [],
$template_types,
$this->type_aliases,
);

View File

@ -1482,7 +1482,7 @@ function bin2hex(string $string): string {}
*
* @param resource|null $context
*
* @return ($associative is 0 ? list<string> : array<string, string|list<string>>)|false
* @return ($associative is false|0 ? list<string> : array<string, string|list<string>>)|false
*
* @psalm-taint-sink ssrf $url
*/

View File

@ -221,3 +221,14 @@ class DatePeriod implements IteratorAggregate
/** @psalm-return (Start is string ? (Traversable<int, DateTime>&Iterator) : (Traversable<int, Start>&Iterator)) */
public function getIterator(): Iterator {}
}
/**
* @psalm-pure
*
* @param resource|null $context
*
* @return ($associative is false|0 ? list<string> : array<string, string|list<string>>)|false
*
* @psalm-taint-sink ssrf $url
*/
function get_headers(string $url, bool $associative = false, $context = null) : array|false {}

View File

@ -1,554 +1,556 @@
<?php
/**
* @generate-function-entries
* @generate-legacy-arginfo
* @see https://github.com/phpredis/phpredis/blob/develop/redis.stub.php
* @see https://github.com/phpredis/phpredis/blob/develop/redis_array.stub.php
* @see https://github.com/phpredis/phpredis/blob/develop/redis_cluster.stub.php
* @see https://github.com/phpredis/phpredis/blob/develop/redis_sentinel.stub.php
*/
class Redis {
public function __construct(array $options = null);
public function __construct(array $options = null) {}
public function _compress(string $value): string;
public function _compress(string $value): string {}
public function __destruct();
public function __destruct() {}
public function _pack(mixed $value): string;
public function _pack(mixed $value): string {}
public function _prefix(string $key): string;
public function _prefix(string $key): string {}
public function _serialize(mixed $value): string;
public function _serialize(mixed $value): string {}
public function _uncompress(string $value): string;
public function _uncompress(string $value): string {}
public function _unpack(string $value): mixed;
public function _unpack(string $value): mixed {}
public function _unserialize(string $value): mixed;
public function _unserialize(string $value): mixed {}
/**
* @param string $args
* @return mixed|Redis
*/
public function acl(string $subcmd, ...$args);
public function acl(string $subcmd, ...$args) {}
/** @return false|int|Redis */
public function append(string $key, string $value);
public function append(string $key, string $value) {}
public function auth(mixed $credentials): bool;
public function auth(mixed $credentials): bool {}
public function bgSave(): bool;
public function bgSave(): bool {}
public function bgrewriteaof(): bool;
public function bgrewriteaof(): bool {}
/** @return false|int|Redis */
public function bitcount(string $key, int $start = 0, int $end = -1);
public function bitcount(string $key, int $start = 0, int $end = -1) {}
/**
* @return false|int|Redis
*/
public function bitop(string $operation, string $deskey, string $srckey, string ...$other_keys): int;
public function bitop(string $operation, string $deskey, string $srckey, string ...$other_keys): int {}
/** @return false|int|Redis */
public function bitpos(string $key, int $bit, int $start = 0, int $end = -1);
public function bitpos(string $key, int $bit, int $start = 0, int $end = -1) {}
public function blPop(string|array $key, string|int $timeout_or_key, mixed ...$extra_args): array|null|false;
public function blPop(string|array $key, string|int $timeout_or_key, mixed ...$extra_args): array|null|false {}
public function brPop(string|array $key, string|int $timeout_or_key, mixed ...$extra_args): array|null|false;
public function brPop(string|array $key, string|int $timeout_or_key, mixed ...$extra_args): array|null|false {}
public function brpoplpush(string $src, string $dst, int $timeout): Redis|string|false;
public function brpoplpush(string $src, string $dst, int $timeout): Redis|string|false {}
public function bzPopMax(string|array $key, string|int $timeout_or_key, mixed ...$extra_args): array|false;
public function bzPopMax(string|array $key, string|int $timeout_or_key, mixed ...$extra_args): array|false {}
public function bzPopMin(string|array $key, string|int $timeout_or_key, mixed ...$extra_args): array|false;
public function bzPopMin(string|array $key, string|int $timeout_or_key, mixed ...$extra_args): array|false {}
public function clearLastError(): bool;
public function clearLastError(): bool {}
public function client(string $opt, string $arg = null): mixed;
public function client(string $opt, string $arg = null): mixed {}
public function close(): bool;
public function close(): bool {}
public function command(string $opt = null, string|array $arg): mixed;
public function command(string $opt = null, string|array $arg): mixed {}
public function config(string $operation, string $key, mixed $value = null): mixed;
public function config(string $operation, string $key, mixed $value = null): mixed {}
public function connect(string $host, int $port = 6379, float $timeout = 0, string $persistent_id = null, int $retry_interval = 0, float $read_timeout = 0, array $context = null): bool;
public function connect(string $host, int $port = 6379, float $timeout = 0, string $persistent_id = null, int $retry_interval = 0, float $read_timeout = 0, array $context = null): bool {}
public function copy(string $src, string $dst, array $options = null): bool;
public function copy(string $src, string $dst, array $options = null): bool {}
public function dbSize(): int;
public function dbSize(): int {}
public function debug(string $key): string;
public function debug(string $key): string {}
/** @return false|int|Redis */
public function decr(string $key, int $by = 1);
public function decr(string $key, int $by = 1) {}
/** @return false|int|Redis */
public function decrBy(string $key, int $value);
public function decrBy(string $key, int $value) {}
/**
* @return false|int|Redis
*/
public function del(array|string $key, string ...$other_keys);
public function del(array|string $key, string ...$other_keys) {}
/**
* @deprecated
* @alias Redis::del
* @return false|int|Redis
*/
public function delete(array|string $key, string ...$other_keys);
public function delete(array|string $key, string ...$other_keys) {}
public function discard(): bool;
public function discard(): bool {}
public function dump(string $key): string;
public function dump(string $key): string {}
/** @return false|string|Redis */
public function echo(string $str);
public function echo(string $str) {}
public function eval(string $script, array $keys = null, int $num_keys = 0): mixed;
public function eval(string $script, array $keys = null, int $num_keys = 0): mixed {}
public function evalsha(string $sha1, array $keys = null, int $num_keys = 0): mixed;
public function evalsha(string $sha1, array $keys = null, int $num_keys = 0): mixed {}
public function exec(): Redis|array|false;
public function exec(): Redis|array|false {}
/** @return int|Redis|bool */
public function exists(mixed $key, mixed ...$other_keys);
public function exists(mixed $key, mixed ...$other_keys) {}
public function expire(string $key, int $timeout): Redis|bool;
public function expire(string $key, int $timeout): Redis|bool {}
public function expireAt(string $key, int $timestamp): Redis|bool;
public function expireAt(string $key, int $timestamp): Redis|bool {}
public function flushAll(bool $async = false): bool;
public function flushAll(bool $async = false): bool {}
public function flushDB(bool $async = false): bool;
public function flushDB(bool $async = false): bool {}
public function geoadd(string $key, float $lng, float $lat, string $member, mixed ...$other_triples): int;
public function geoadd(string $key, float $lng, float $lat, string $member, mixed ...$other_triples): int {}
public function geodist(string $key, string $src, string $dst, ?string $unit = null): Redis|float|false;
public function geodist(string $key, string $src, string $dst, ?string $unit = null): Redis|float|false {}
public function geohash(string $key, string $member, string ...$other_members): array|false;
public function geohash(string $key, string $member, string ...$other_members): array|false {}
public function geopos(string $key, string $member, string ...$other_members): Redis|array|false;
public function geopos(string $key, string $member, string ...$other_members): Redis|array|false {}
public function georadius(string $key, float $lng, float $lat, float $radius, string $unit, array $options = []): Redis|mixed|false;
public function georadius(string $key, float $lng, float $lat, float $radius, string $unit, array $options = []): Redis|mixed|false {}
public function georadius_ro(string $key, float $lng, float $lat, float $radius, string $unit, array $options = []): Redis|mixed|false;
public function georadius_ro(string $key, float $lng, float $lat, float $radius, string $unit, array $options = []): Redis|mixed|false {}
public function georadiusbymember(string $key, string $member, float $radius, string $unit, array $options = []): Redis|mixed|false;
public function georadiusbymember(string $key, string $member, float $radius, string $unit, array $options = []): Redis|mixed|false {}
public function georadiusbymember_ro(string $key, string $member, float $radius, string $unit, array $options = []): Redis|mixed|false;
public function georadiusbymember_ro(string $key, string $member, float $radius, string $unit, array $options = []): Redis|mixed|false {}
public function geosearch(string $key, array|string $position, array|int|float $shape, string $unit, array $options = []): array|false;
public function geosearch(string $key, array|string $position, array|int|float $shape, string $unit, array $options = []): array|false {}
public function geosearchstore(string $dst, string $src, array|string $position, array|int|float $shape, string $unit, array $options = []): array|false;
public function geosearchstore(string $dst, string $src, array|string $position, array|int|float $shape, string $unit, array $options = []): array|false {}
/** @return false|string|Redis */
public function get(string $key);
public function get(string $key) {}
public function getAuth(): mixed;
public function getAuth(): mixed {}
/** @return false|int|Redis */
public function getBit(string $key, int $idx);
public function getBit(string $key, int $idx) {}
public function getDBNum(): int;
public function getDBNum(): int {}
public function getHost(): string;
public function getHost(): string {}
public function getLastError(): ?string;
public function getLastError(): ?string {}
public function getMode(): int;
public function getMode(): int {}
public function getOption(int $option): mixed;
public function getOption(int $option): mixed {}
public function getPersistentID(): ?string;
public function getPersistentID(): ?string {}
public function getPort(): int;
public function getPort(): int {}
/** @return false|string|Redis */
public function getRange(string $key, int $start, int $end);
public function getRange(string $key, int $start, int $end) {}
public function getReadTimeout(): int;
public function getReadTimeout(): int {}
/** @return false|string|Redis */
public function getset(string $key, string $value);
public function getset(string $key, string $value) {}
public function getTimeout(): int;
public function getTimeout(): int {}
public function hDel(string $key, string $member, string ...$other_members): Redis|int|false;
public function hDel(string $key, string $member, string ...$other_members): Redis|int|false {}
public function hExists(string $key, string $member): Redis|bool;
public function hExists(string $key, string $member): Redis|bool {}
public function hGet(string $key, string $member): Redis|mixed|false;
public function hGet(string $key, string $member): Redis|mixed|false {}
public function hGetAll(string $key): Redis|array|false;
public function hGetAll(string $key): Redis|array|false {}
public function hIncrBy(string $key, string $member, int $value): Redis|int|false;
public function hIncrBy(string $key, string $member, int $value): Redis|int|false {}
public function hIncrByFloat(string $key, string $member, float $value): Redis|float|false;
public function hIncrByFloat(string $key, string $member, float $value): Redis|float|false {}
public function hKeys(string $key): Redis|array|false;
public function hKeys(string $key): Redis|array|false {}
public function hLen(string $key): Redis|int|false;
public function hLen(string $key): Redis|int|false {}
public function hMget(string $key, array $keys): Redis|array|false;
public function hMget(string $key, array $keys): Redis|array|false {}
public function hMset(string $key, array $keyvals): Redis|bool|false;
public function hMset(string $key, array $keyvals): Redis|bool|false {}
public function hSet(string $key, string $member, string $value): Redis|int|false;
public function hSet(string $key, string $member, string $value): Redis|int|false {}
public function hSetNx(string $key, string $member, string $value): Redis|bool;
public function hSetNx(string $key, string $member, string $value): Redis|bool {}
public function hStrLen(string $key, string $member): int;
public function hStrLen(string $key, string $member): int {}
public function hVals(string $key): Redis|array|false;
public function hVals(string $key): Redis|array|false {}
public function hscan(string $key, ?int &$iterator, ?string $pattern = null, int $count = 0): bool|array;
public function hscan(string $key, ?int &$iterator, ?string $pattern = null, int $count = 0): bool|array {}
/** @return false|int|Redis */
public function incr(string $key, int $by = 1);
public function incr(string $key, int $by = 1) {}
/** @return false|int|Redis */
public function incrBy(string $key, int $value);
public function incrBy(string $key, int $value) {}
/** @return false|int|Redis */
public function incrByFloat(string $key, float $value);
public function incrByFloat(string $key, float $value) {}
public function info(string $opt = null): Redis|array|false;
public function info(string $opt = null): Redis|array|false {}
public function isConnected(): bool;
public function isConnected(): bool {}
/** @return false|array|Redis */
public function keys(string $pattern);
public function keys(string $pattern) {}
/**
* @param mixed $elements
* @return false|int|Redis
*/
public function lInsert(string $key, string $pos, mixed $pivot, mixed $value);
public function lInsert(string $key, string $pos, mixed $pivot, mixed $value) {}
public function lLen(string $key): Redis|int|false;
public function lLen(string $key): Redis|int|false {}
public function lMove(string $src, string $dst, string $wherefrom, string $whereto): string;
public function lMove(string $src, string $dst, string $wherefrom, string $whereto): string {}
/** @return false|string|Redis */
public function lPop(string $key);
public function lPop(string $key) {}
/**
* @param mixed $elements
* @return false|int|Redis
*/
public function lPush(string $key, ...$elements);
public function lPush(string $key, ...$elements) {}
/**
* @param mixed $elements
* @return false|int|Redis
*/
public function rPush(string $key, ...$elements);
public function rPush(string $key, ...$elements) {}
/** @return false|int|Redis */
public function lPushx(string $key, string $value);
public function lPushx(string $key, string $value) {}
/** @return false|int|Redis */
public function rPushx(string $key, string $value);
public function rPushx(string $key, string $value) {}
public function lSet(string $key, int $index, string $value): Redis|bool;
public function lSet(string $key, int $index, string $value): Redis|bool {}
public function lastSave(): int;
public function lastSave(): int {}
public function lindex(string $key, int $index): Redis|mixed|false;
public function lindex(string $key, int $index): Redis|mixed|false {}
public function lrange(string $key, int $start , int $end): Redis|array|false;
public function lrange(string $key, int $start , int $end): Redis|array|false {}
/**
* @return int|Redis|false
*/
public function lrem(string $key, string $value, int $count = 0);
public function lrem(string $key, string $value, int $count = 0) {}
public function ltrim(string $key, int $start , int $end): Redis|bool;
public function ltrim(string $key, int $start , int $end): Redis|bool {}
/** @return false|list<false|string>|Redis */
public function mget(array $keys);
public function mget(array $keys) {}
public function migrate(string $host, int $port, string $key, string $dst, int $timeout, bool $copy = false, bool $replace = false): bool;
public function migrate(string $host, int $port, string $key, string $dst, int $timeout, bool $copy = false, bool $replace = false): bool {}
public function move(string $key, int $index): bool;
public function move(string $key, int $index): bool {}
/**
* @param array<string, string>
*/
public function mset($key_values): Redis|bool;
public function mset($key_values): Redis|bool {}
/**
* @param array<string, string>
*/
public function msetnx($key_values): Redis|bool;
public function msetnx($key_values): Redis|bool {}
public function multi(int $value = Redis::MULTI): bool|Redis;
public function multi(int $value = Redis::MULTI): bool|Redis {}
public function object(string $subcommand, string $key): Redis|int|string|false;
public function object(string $subcommand, string $key): Redis|int|string|false {}
/**
* @deprecated
* @alias Redis::connect
*/
public function open(string $host, int $port = 6379, float $timeout = 0, string $persistent_id = NULL, int $retry_interval = 0, float $read_timeout = 0, array $context = NULL): bool;
public function open(string $host, int $port = 6379, float $timeout = 0, string $persistent_id = NULL, int $retry_interval = 0, float $read_timeout = 0, array $context = NULL): bool {}
public function pconnect(string $host, int $port = 6379, float $timeout = 0, string $persistent_id = NULL, int $retry_interval = 0, float $read_timeout = 0, array $context = NULL): bool;
public function pconnect(string $host, int $port = 6379, float $timeout = 0, string $persistent_id = NULL, int $retry_interval = 0, float $read_timeout = 0, array $context = NULL): bool {}
public function persist(string $key): bool;
public function persist(string $key): bool {}
public function pexpire(string $key, int $timeout): bool;
public function pexpire(string $key, int $timeout): bool {}
public function pexpireAt(string $key, int $timestamp): bool;
public function pexpireAt(string $key, int $timestamp): bool {}
public function pfadd(string $key, array $elements): int;
public function pfadd(string $key, array $elements): int {}
public function pfcount(string $key): int;
public function pfcount(string $key): int {}
public function pfmerge(string $dst, array $keys): bool;
public function pfmerge(string $dst, array $keys): bool {}
/** @return false|string|Redis */
public function ping(string $key = NULL);
public function ping(string $key = NULL) {}
public function pipeline(): bool|Redis;
public function pipeline(): bool|Redis {}
/**
* @deprecated
* @alias Redis::pconnect
*/
public function popen(string $host, int $port = 6379, float $timeout = 0, string $persistent_id = NULL, int $retry_interval = 0, float $read_timeout = 0, array $context = NULL): bool;
public function popen(string $host, int $port = 6379, float $timeout = 0, string $persistent_id = NULL, int $retry_interval = 0, float $read_timeout = 0, array $context = NULL): bool {}
/** @return bool|Redis */
public function psetex(string $key, int $expire, string $value);
public function psetex(string $key, int $expire, string $value) {}
public function psubscribe(array $patterns): void;
public function psubscribe(array $patterns): void {}
public function pttl(string $key): Redis|int|false;
public function pttl(string $key): Redis|int|false {}
public function publish(string $channel, string $message): mixed;
public function publish(string $channel, string $message): mixed {}
public function pubsub(string $command, mixed $arg = null): mixed;
public function pubsub(string $command, mixed $arg = null): mixed {}
public function punsubscribe(array $patterns): array|false;
public function punsubscribe(array $patterns): array|false {}
/** @return false|string|Redis */
public function rPop(string $key);
public function rPop(string $key) {}
/** @return false|string|Redis */
public function randomKey();
public function randomKey() {}
public function rawcommand(string $command, mixed ...$args): mixed;
public function rawcommand(string $command, mixed ...$args): mixed {}
/** @return bool|Redis */
public function rename(string $key_src, string $key_dst);
public function rename(string $key_src, string $key_dst) {}
/** @return bool|Redis */
public function renameNx(string $key_src, string $key_dst);
public function renameNx(string $key_src, string $key_dst) {}
public function restore(string $key, int $timeout, string $value): bool;
public function restore(string $key, int $timeout, string $value): bool {}
public function role(): mixed;
public function role(): mixed {}
public function rpoplpush(string $src, string $dst): Redis|string|false;
public function rpoplpush(string $src, string $dst): Redis|string|false {}
public function sAdd(string $key, string $value, mixed ...$other_values): Redis|int|false;
public function sAdd(string $key, string $value, mixed ...$other_values): Redis|int|false {}
public function sAddArray(string $key, array $values): int;
public function sAddArray(string $key, array $values): int {}
public function sDiff(string $key, string ...$other_keys): Redis|array|false;
public function sDiff(string $key, string ...$other_keys): Redis|array|false {}
public function sDiffStore(string $dst, string $key, string ...$other_keys): Redis|int|false;
public function sDiffStore(string $dst, string $key, string ...$other_keys): Redis|int|false {}
public function sInter(array|string $key, string ...$other_keys): Redis|array|false;
public function sInter(array|string $key, string ...$other_keys): Redis|array|false {}
public function sInterStore(array|string $key, string ...$other_keys): Redis|int|false;
public function sInterStore(array|string $key, string ...$other_keys): Redis|int|false {}
public function sMembers(string $key): Redis|array|false;
public function sMembers(string $key): Redis|array|false {}
public function sMisMember(string $key, string $member, string ...$other_members): array|false;
public function sMisMember(string $key, string $member, string ...$other_members): array|false {}
public function sMove(string $src, string $dst, string $value): Redis|bool;
public function sMove(string $src, string $dst, string $value): Redis|bool {}
public function sPop(string $key, int $count = 0): Redis|string|array|false;
public function sPop(string $key, int $count = 0): Redis|string|array|false {}
public function sRandMember(string $key, int $count = 0): Redis|string|array|false;
public function sRandMember(string $key, int $count = 0): Redis|string|array|false {}
public function sUnion(string $key, string ...$other_keys): Redis|array|false;
public function sUnion(string $key, string ...$other_keys): Redis|array|false {}
public function sUnionStore(string $dst, string $key, string ...$other_keys): Redis|int|false;
public function sUnionStore(string $dst, string $key, string ...$other_keys): Redis|int|false {}
public function save(): bool;
public function save(): bool {}
public function scan(?int &$iterator, ?string $pattern = null, int $count = 0, string $type = NULL): array|false;
public function scan(?int &$iterator, ?string $pattern = null, int $count = 0, string $type = NULL): array|false {}
public function scard(string $key): Redis|int|false;
public function scard(string $key): Redis|int|false {}
public function script(string $command, mixed ...$args): mixed;
public function script(string $command, mixed ...$args): mixed {}
public function select(int $db): bool;
public function select(int $db): bool {}
/** @return bool|Redis */
public function set(string $key, string $value, mixed $opt = NULL);
public function set(string $key, string $value, mixed $opt = NULL) {}
/** @return false|int|Redis */
public function setBit(string $key, int $idx, bool $value);
public function setBit(string $key, int $idx, bool $value) {}
/** @return false|int|Redis */
public function setRange(string $key, int $start, string $value);
public function setRange(string $key, int $start, string $value) {}
public function setOption(int $option, mixed $value): bool;
public function setOption(int $option, mixed $value): bool {}
/** @return bool|Redis */
public function setex(string $key, int $expire, string $value);
public function setex(string $key, int $expire, string $value) {}
/** @return bool|array|Redis */
public function setnx(string $key, string $value);
public function setnx(string $key, string $value) {}
public function sismember(string $key, string $value): Redis|bool;
public function sismember(string $key, string $value): Redis|bool {}
public function slaveof(string $host = null, int $port = 6379): bool;
public function slaveof(string $host = null, int $port = 6379): bool {}
public function slowlog(string $mode, int $option = 0): mixed;
public function slowlog(string $mode, int $option = 0): mixed {}
public function sort(string $key, array $options = null): mixed;
public function sort(string $key, array $options = null): mixed {}
/**
* @deprecated
*/
public function sortAsc(string $key, ?string $pattern = null, mixed $get = null, int $offset = -1, int $count = -1, ?string $store = null): array;
public function sortAsc(string $key, ?string $pattern = null, mixed $get = null, int $offset = -1, int $count = -1, ?string $store = null): array {}
/**
* @deprecated
*/
public function sortAscAlpha(string $key, ?string $pattern = null, mixed $get = null, int $offset = -1, int $count = -1, ?string $store = null): array;
public function sortAscAlpha(string $key, ?string $pattern = null, mixed $get = null, int $offset = -1, int $count = -1, ?string $store = null): array {}
/**
* @deprecated
*/
public function sortDesc(string $key, ?string $pattern = null, mixed $get = null, int $offset = -1, int $count = -1, ?string $store = null): array;
public function sortDesc(string $key, ?string $pattern = null, mixed $get = null, int $offset = -1, int $count = -1, ?string $store = null): array {}
/**
* @deprecated
*/
public function sortDescAlpha(string $key, ?string $pattern = null, mixed $get = null, int $offset = -1, int $count = -1, ?string $store = null): array;
public function sortDescAlpha(string $key, ?string $pattern = null, mixed $get = null, int $offset = -1, int $count = -1, ?string $store = null): array {}
public function srem(string $key, string $value, mixed ...$other_values): Redis|int|false;
public function srem(string $key, string $value, mixed ...$other_values): Redis|int|false {}
public function sscan(string $key, int &$iterator, ?string $pattern = null, int $count = 0): array|false;
public function sscan(string $key, int &$iterator, ?string $pattern = null, int $count = 0): array|false {}
/** @return false|int|Redis */
public function strlen(string $key);
public function strlen(string $key) {}
public function subscribe(string $channel, string ...$other_channels): array|false;
public function subscribe(string $channel, string ...$other_channels): array|false {}
public function swapdb(string $src, string $dst): bool;
public function swapdb(string $src, string $dst): bool {}
public function time(): array|false;
public function time(): array|false {}
public function ttl(string $key): Redis|int|false;
public function ttl(string $key): Redis|int|false {}
/** @return false|int|Redis */
public function type(string $key);
public function type(string $key) {}
/**
* @return false|int|Redis
*/
public function unlink(array|string $key, string ...$other_keys);
public function unlink(array|string $key, string ...$other_keys) {}
public function unsubscribe(string $channel, string ...$other_channels): array|false;
public function unsubscribe(string $channel, string ...$other_channels): array|false {}
/** @return bool|Redis */
public function unwatch();
public function unwatch() {}
/**
* @return bool|Redis
*/
public function watch(array|string $key, string ...$other_keys);
public function watch(array|string $key, string ...$other_keys) {}
public function wait(int $count, int $timeout): int|false;
public function wait(int $count, int $timeout): int|false {}
public function xack(string $key, string $group, array $ids): int|false;
public function xack(string $key, string $group, array $ids): int|false {}
public function xadd(string $key, string $id, array $values, int $maxlen = 0, bool $approx = false): string|false;
public function xadd(string $key, string $id, array $values, int $maxlen = 0, bool $approx = false): string|false {}
public function xclaim(string $key, string $group, string $consumer, int $min_iddle, array $ids, array $options): string|array|false;
public function xclaim(string $key, string $group, string $consumer, int $min_iddle, array $ids, array $options): string|array|false {}
public function xdel(string $key, array $ids): Redis|int|false;
public function xdel(string $key, array $ids): Redis|int|false {}
public function xgroup(string $operation, string $key = null, string $arg1 = null, string $arg2 = null, bool $arg3 = false): mixed;
public function xgroup(string $operation, string $key = null, string $arg1 = null, string $arg2 = null, bool $arg3 = false): mixed {}
public function xinfo(string $operation, ?string $arg1 = null, ?string $arg2 = null, int $count = -1): mixed;
public function xinfo(string $operation, ?string $arg1 = null, ?string $arg2 = null, int $count = -1): mixed {}
public function xlen(string $key): int;
public function xlen(string $key): int {}
public function xpending(string $key, string $group, string $start = null, string $end = null, int $count = -1, string $consumer = null): Redis|array|false;
public function xpending(string $key, string $group, string $start = null, string $end = null, int $count = -1, string $consumer = null): Redis|array|false {}
public function xrange(string $key, string $start, string $end, int $count = -1): bool|array;
public function xrange(string $key, string $start, string $end, int $count = -1): bool|array {}
public function xread(array $streams, int $count = -1, int $block = -1): bool|array;
public function xread(array $streams, int $count = -1, int $block = -1): bool|array {}
public function xreadgroup(string $group, string $consumer, array $streams, int $count = 1, int $block = 1): bool|array;
public function xreadgroup(string $group, string $consumer, array $streams, int $count = 1, int $block = 1): bool|array {}
public function xrevrange(string $key, string $start, string $end, int $count = -1): bool|array;
public function xrevrange(string $key, string $start, string $end, int $count = -1): bool|array {}
public function xtrim(string $key, int $maxlen, bool $approx = false): int;
public function xtrim(string $key, int $maxlen, bool $approx = false): int {}
public function zAdd(string $key, array|float $score_or_options, mixed ...$more_scores_and_mems): Redis|int|false;
public function zAdd(string $key, array|float $score_or_options, mixed ...$more_scores_and_mems): Redis|int|false {}
public function zCard(string $key): Redis|int|false;
public function zCard(string $key): Redis|int|false {}
public function zCount(string $key, string $start , string $end): Redis|int|false;
public function zCount(string $key, string $start , string $end): Redis|int|false {}
public function zIncrBy(string $key, float $value, mixed $member): Redis|float|false;
public function zIncrBy(string $key, float $value, mixed $member): Redis|float|false {}
public function zLexCount(string $key, string $min, string $max): Redis|int|false;
public function zLexCount(string $key, string $min, string $max): Redis|int|false {}
public function zMscore(string $key, string $member, string ...$other_members): array|false;
public function zMscore(string $key, string $member, string ...$other_members): array|false {}
public function zPopMax(string $key, int $value = null): array|false;
public function zPopMax(string $key, int $value = null): array|false {}
public function zPopMin(string $key, int $value = null): array|false;
public function zPopMin(string $key, int $value = null): array|false {}
public function zRange(string $key, int $start, int $end, mixed $scores = null): Redis|array|false;
public function zRange(string $key, int $start, int $end, mixed $scores = null): Redis|array|false {}
public function zRangeByLex(string $key, string $min, string $max, int $offset = -1, int $count = -1): array|false;
public function zRangeByLex(string $key, string $min, string $max, int $offset = -1, int $count = -1): array|false {}
public function zRangeByScore(string $key, string $start, string $end, array $options = []): Redis|array|false;
public function zRangeByScore(string $key, string $start, string $end, array $options = []): Redis|array|false {}
public function zRandMember(string $key, array $options = null): string|array|false;
public function zRandMember(string $key, array $options = null): string|array|false {}
public function zRank(string $key, mixed $member): Redis|int|false;
public function zRank(string $key, mixed $member): Redis|int|false {}
public function zRem(mixed $key, mixed $member, mixed ...$other_members): Redis|int|false;
public function zRem(mixed $key, mixed $member, mixed ...$other_members): Redis|int|false {}
public function zRemRangeByLex(string $key, string $min, string $max): int|false;
public function zRemRangeByLex(string $key, string $min, string $max): int|false {}
public function zRemRangeByRank(string $key, int $start, int $end): Redis|int|false;
public function zRemRangeByRank(string $key, int $start, int $end): Redis|int|false {}
public function zRemRangeByScore(string $key, string $start, string $end): Redis|int|false;
public function zRemRangeByScore(string $key, string $start, string $end): Redis|int|false {}
public function zRevRange(string $key, int $start, int $end, mixed $scores = null): Redis|array|false;
public function zRevRange(string $key, int $start, int $end, mixed $scores = null): Redis|array|false {}
public function zRevRangeByLex(string $key, string $min, string $max, int $offset = -1, int $count = -1): array|false;
public function zRevRangeByLex(string $key, string $min, string $max, int $offset = -1, int $count = -1): array|false {}
public function zRevRangeByScore(string $key, string $start, string $end, array $options = []): array|false;
public function zRevRangeByScore(string $key, string $start, string $end, array $options = []): array|false {}
public function zRevRank(string $key, mixed $member): Redis|int|false;
public function zRevRank(string $key, mixed $member): Redis|int|false {}
public function zScore(string $key, mixed $member): Redis|float|false;
public function zScore(string $key, mixed $member): Redis|float|false {}
public function zdiff(array $keys, array $options = null): array|false;
public function zdiff(array $keys, array $options = null): array|false {}
public function zdiffstore(string $dst, array $keys, array $options = null): int;
public function zdiffstore(string $dst, array $keys, array $options = null): int {}
public function zinter(array $keys, ?array $weights = null, ?array $options = null): Redis|array|false;
public function zinter(array $keys, ?array $weights = null, ?array $options = null): Redis|array|false {}
public function zinterstore(string $dst, array $keys, ?array $weights = null, ?string $aggregate = null): Redis|int|false;
public function zinterstore(string $dst, array $keys, ?array $weights = null, ?string $aggregate = null): Redis|int|false {}
public function zscan(string $key, ?int &$iterator, ?string $pattern = null, int $count = 0): bool|array;
public function zscan(string $key, ?int &$iterator, ?string $pattern = null, int $count = 0): bool|array {}
public function zunion(array $keys, ?array $weights = null, ?array $options = null): Redis|array|false;
public function zunion(array $keys, ?array $weights = null, ?array $options = null): Redis|array|false {}
public function zunionstore(string $dst, array $keys, ?array $weights = NULL, ?string $aggregate = NULL): Redis|int|false;
public function zunionstore(string $dst, array $keys, ?array $weights = NULL, ?string $aggregate = NULL): Redis|int|false {}
}

View File

@ -2045,6 +2045,24 @@ class FunctionCallTest extends TestCase
}
',
],
'getHeadersAssociativeIn8x' => [
'code' => '<?php
$a = get_headers("https://psalm.dev", true);',
'assertions' => [
'$a' => 'array<string, list<string>|string>|false',
],
'ignored_issues' => [],
'php_version' => '8.0',
],
'getHeadersAssociativeIn7x' => [
'code' => '<?php
$a = get_headers("https://psalm.dev", 0);',
'assertions' => [
'$a' => 'false|list<string>',
],
'ignored_issues' => [],
'php_version' => '7.0',
],
];
}

View File

@ -211,7 +211,6 @@ class InternalCallMapHandlerTest extends TestCase
'finfo::file',
'finfo::set_flags',
'generator::throw',
'get_headers',
'globiterator::__construct',
'globiterator::getfileinfo',
'globiterator::getpathinfo',

View File

@ -4029,6 +4029,28 @@ class ClassTemplateTest extends TestCase
$baz = new DoesNotExist();
foobar($baz);',
],
'promoted property with template' => [
'code' => '<?php
/**
* @template T
*/
class A {
public function __construct(
/** @var T */
public mixed $t
) {}
}
$a = new A(5);
$t = $a->t;
',
'assertions' => [
'$a' => 'A<int>',
'$t' => 'int',
],
'ignored_issues' => [],
'php_version' => '8.0',
],
];
}