diff --git a/.github/workflows/macos-scan.yml b/.github/workflows/macos-scan.yml
new file mode 100644
index 00000000000..c298a291362
--- /dev/null
+++ b/.github/workflows/macos-scan.yml
@@ -0,0 +1,29 @@
+name: Run Psalm (mac OS)
+
+on: [push, pull_request]
+
+permissions:
+ contents: read
+
+jobs:
+ build:
+ runs-on: macos-15
+
+ steps:
+ - uses: actions/checkout@v4
+ - uses: shivammathur/setup-php@v2
+ with:
+ php-version: '8.4'
+ ini-values: zend.assertions=1
+ tools: composer:v2
+ coverage: none
+ env:
+ fail-fast: true
+
+ - name: Install dependencies
+ run: composer install --prefer-dist --no-progress --no-suggest
+ env:
+ COMPOSER_ROOT_VERSION: dev-master
+
+ - name: Run Psalm
+ run: ./psalm --output-format=github
diff --git a/.github/workflows/shepherd.yml b/.github/workflows/shepherd.yml
index 3440783d936..d11fed5aaa1 100644
--- a/.github/workflows/shepherd.yml
+++ b/.github/workflows/shepherd.yml
@@ -13,7 +13,7 @@ jobs:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
- php-version: '8.2'
+ php-version: '8.4'
ini-values: zend.assertions=1
tools: composer:v2
coverage: none
@@ -26,4 +26,4 @@ jobs:
COMPOSER_ROOT_VERSION: dev-master
- name: Run Psalm
- run: ./psalm --threads=2 --output-format=github --shepherd
+ run: ./psalm --output-format=github --shepherd
diff --git a/composer.json b/composer.json
index 6384250bc36..98e159def3e 100644
--- a/composer.json
+++ b/composer.json
@@ -15,7 +15,7 @@
}
],
"require": {
- "php": "~8.1.17 || ~8.2.4 || ~8.3.0",
+ "php": "~8.1.17 || ~8.2.4 || ~8.3.0 || ~8.4.0",
"ext-SimpleXML": "*",
"ext-ctype": "*",
"ext-dom": "*",
diff --git a/config.xsd b/config.xsd
index 55aedabe061..b58a3bbb9d7 100644
--- a/config.xsd
+++ b/config.xsd
@@ -315,6 +315,7 @@
+
diff --git a/dictionaries/CallMap.php b/dictionaries/CallMap.php
index 80de3809a85..48e23a2c603 100644
--- a/dictionaries/CallMap.php
+++ b/dictionaries/CallMap.php
@@ -1142,17 +1142,17 @@
'crash' => [''],
'crc32' => ['int', 'string'=>'string'],
'crypt' => ['string', 'string'=>'string', 'salt'=>'string'],
-'ctype_alnum' => ['bool', 'text'=>'string|int'],
-'ctype_alpha' => ['bool', 'text'=>'string|int'],
-'ctype_cntrl' => ['bool', 'text'=>'string|int'],
-'ctype_digit' => ['bool', 'text'=>'string|int'],
-'ctype_graph' => ['bool', 'text'=>'string|int'],
-'ctype_lower' => ['bool', 'text'=>'string|int'],
-'ctype_print' => ['bool', 'text'=>'string|int'],
-'ctype_punct' => ['bool', 'text'=>'string|int'],
-'ctype_space' => ['bool', 'text'=>'string|int'],
-'ctype_upper' => ['bool', 'text'=>'string|int'],
-'ctype_xdigit' => ['bool', 'text'=>'string|int'],
+'ctype_alnum' => ['bool', 'text'=>'string'],
+'ctype_alpha' => ['bool', 'text'=>'string'],
+'ctype_cntrl' => ['bool', 'text'=>'string'],
+'ctype_digit' => ['bool', 'text'=>'string'],
+'ctype_graph' => ['bool', 'text'=>'string'],
+'ctype_lower' => ['bool', 'text'=>'string'],
+'ctype_print' => ['bool', 'text'=>'string'],
+'ctype_punct' => ['bool', 'text'=>'string'],
+'ctype_space' => ['bool', 'text'=>'string'],
+'ctype_upper' => ['bool', 'text'=>'string'],
+'ctype_xdigit' => ['bool', 'text'=>'string'],
'cubrid_affected_rows' => ['int', 'req_identifier='=>''],
'cubrid_bind' => ['bool', 'req_identifier'=>'resource', 'bind_param'=>'int', 'bind_value'=>'mixed', 'bind_value_type='=>'string'],
'cubrid_client_encoding' => ['string', 'conn_identifier='=>''],
@@ -1293,7 +1293,7 @@
'CURLFile::setMimeType' => ['void', 'mime_type'=>'string'],
'CURLFile::setPostFilename' => ['void', 'posted_filename'=>'string'],
'CURLStringFile::__construct' => ['void', 'data'=>'string', 'postname'=>'string', 'mime='=>'string'],
-'current' => ['mixed|false', 'array'=>'array|object'],
+'current' => ['mixed|false', 'array'=>'array'],
'cyrus_authenticate' => ['void', 'connection'=>'resource', 'mechlist='=>'string', 'service='=>'string', 'user='=>'string', 'minssf='=>'int', 'maxssf='=>'int', 'authname='=>'string', 'password='=>'string'],
'cyrus_bind' => ['bool', 'connection'=>'resource', 'callbacks'=>'array'],
'cyrus_close' => ['bool', 'connection'=>'resource'],
@@ -3269,7 +3269,7 @@
'get_call_stack' => [''],
'get_called_class' => ['class-string'],
'get_cfg_var' => ['string|false', 'option'=>'string'],
-'get_class' => ['class-string', 'object='=>'object'],
+'get_class' => ['class-string', 'object'=>'object'],
'get_class_methods' => ['list', 'object_or_class'=>'object|class-string'],
'get_class_vars' => ['array', 'class'=>'string'],
'get_current_user' => ['string'],
@@ -3290,7 +3290,7 @@
'get_magic_quotes_runtime' => ['int|false'],
'get_meta_tags' => ['array', 'filename'=>'string', 'use_include_path='=>'bool'],
'get_object_vars' => ['array', 'object'=>'object'],
-'get_parent_class' => ['class-string|false', 'object_or_class='=>'object|class-string'],
+'get_parent_class' => ['class-string|false', 'object_or_class'=>'object|class-string'],
'get_required_files' => ['list'],
'get_resource_id' => ['int', 'resource'=>'resource'],
'get_resource_type' => ['string', 'resource'=>'resource'],
@@ -3307,7 +3307,7 @@
'getimagesize' => ['array{0:int, 1: int, 2: int, 3: string, mime: string, channels?: 3|4, bits?: int}|false', 'filename'=>'string', '&w_image_info='=>'array'],
'getimagesizefromstring' => ['array{0:int, 1: int, 2: int, 3: string, mime: string, channels?: 3|4, bits?: int}|false', 'string'=>'string', '&w_image_info='=>'array'],
'getlastmod' => ['int|false'],
-'getmxrr' => ['bool', 'hostname'=>'string', '&w_hosts'=>'array', '&w_weights='=>'array'],
+'getmxrr' => ['bool', 'hostname'=>'string', '&w_hosts'=>'array', '&w_weights='=>'array'],
'getmygid' => ['int|false'],
'getmyinode' => ['int|false'],
'getmypid' => ['int|false'],
@@ -6198,7 +6198,7 @@
'kadm5_get_principals' => ['array', 'handle'=>'resource'],
'kadm5_init_with_password' => ['resource', 'admin_server'=>'string', 'realm'=>'string', 'principal'=>'string', 'password'=>'string'],
'kadm5_modify_principal' => ['bool', 'handle'=>'resource', 'principal'=>'string', 'options'=>'array'],
-'key' => ['int|string|null', 'array'=>'array|object'],
+'key' => ['int|string|null', 'array'=>'array'],
'key_exists' => ['bool', 'key'=>'string|int', 'array'=>'array'],
'krsort' => ['true', '&rw_array'=>'array', 'flags='=>'int'],
'ksort' => ['true', '&rw_array'=>'array', 'flags='=>'int'],
@@ -6446,7 +6446,7 @@
'litespeed_request_headers' => ['array'],
'litespeed_response_headers' => ['array'],
'Locale::acceptFromHttp' => ['string|false', 'header'=>'string'],
-'Locale::canonicalize' => ['string', 'locale'=>'string'],
+'Locale::canonicalize' => ['?string', 'locale'=>'string'],
'Locale::composeLocale' => ['string', 'subtags'=>'array'],
'Locale::filterMatches' => ['?bool', 'languageTag'=>'string', 'locale'=>'string', 'canonicalize='=>'bool'],
'Locale::getAllVariants' => ['array', 'locale'=>'string'],
@@ -6598,7 +6598,7 @@
'mapObj::zoomScale' => ['int', 'nScaleDenom'=>'float', 'oPixelPos'=>'pointObj', 'nImageWidth'=>'int', 'nImageHeight'=>'int', 'oGeorefExt'=>'rectObj', 'oMaxGeorefExt'=>'rectObj'],
'max' => ['mixed', 'value'=>'non-empty-array'],
'max\'1' => ['mixed', 'value'=>'', 'values'=>'', '...args='=>''],
-'mb_check_encoding' => ['bool', 'value='=>'array|string|null', 'encoding='=>'string|null'],
+'mb_check_encoding' => ['bool', 'value'=>'array|string', 'encoding='=>'string|null'],
'mb_chr' => ['non-empty-string|false', 'codepoint'=>'int', 'encoding='=>'string|null'],
'mb_convert_case' => ['string', 'string'=>'string', 'mode'=>'int', 'encoding='=>'string|null'],
'mb_convert_encoding' => ['string|false', 'string'=>'string', 'to_encoding'=>'string', 'from_encoding='=>'array|string|null'],
@@ -7906,9 +7906,9 @@
'mysqli_fetch_array\'2' => ['list|false|null', 'result'=>'mysqli_result', 'mode='=>'2'],
'mysqli_fetch_assoc' => ['array|false|null', 'result'=>'mysqli_result'],
'mysqli_fetch_column' => ['null|int|float|string|false', 'result'=>'mysqli_result', 'column='=>'int'],
-'mysqli_fetch_field' => ['object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}|false', 'result'=>'mysqli_result'],
-'mysqli_fetch_field_direct' => ['object{name:non-empty-string,orgname:string,table:string,orgtable:string,max_length:int,length:int,charsetnr:int,flags:int,type:int,decimals:int,db:string,def:string,catalog:string}|false', 'result'=>'mysqli_result', 'index'=>'int'],
-'mysqli_fetch_fields' => ['list