diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index c01cbfe0954f..d5f4a8a6f4bb 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -16,19 +16,19 @@
/.github @TimWolla
/build/gen_stub.php @kocsismate
-/ext/bcmath @ndossche @SakiTakamachi
+/ext/bcmath @SakiTakamachi
/ext/curl @adoy
/ext/date @derickr
/ext/dba @Girgias
-/ext/dom @ndossche
+/ext/dom @devnexen
/ext/ffi @dstogov
/ext/gd @devnexen
/ext/gettext @devnexen
/ext/gmp @Girgias
/ext/intl @devnexen
+/ext/libxml @devnexen
/ext/json @bukka
-/ext/lexbor @kocsismate @ndossche
-/ext/libxml @ndossche
+/ext/lexbor @kocsismate
/ext/mbstring @alexdowad @youkidearitai
/ext/mysqli @bukka @kamil-tekiela
/ext/mysqlnd @bukka @kamil-tekiela @SakiTakamachi
@@ -47,17 +47,16 @@
/ext/random @TimWolla @zeriyoshi
/ext/reflection @DanielEScherzer
/ext/session @Girgias
-/ext/simplexml @ndossche
-/ext/soap @ndossche
+/ext/simplexml @devnexen
+/ext/soap @devnexen
/ext/sockets @devnexen
/ext/spl @Girgias
/ext/standard @bukka
-/ext/tidy @ndossche
/ext/uri @kocsismate @TimWolla
-/ext/xml @ndossche
-/ext/xmlreader @ndossche
-/ext/xmlwriter @ndossche
-/ext/xsl @ndossche
+/ext/xml @devnexen
+/ext/xmlreader @devnexen
+/ext/xmlwriter @devnexen
+/ext/xsl @devnexen
/main @bukka
/sapi/fpm @bukka
/Zend/Optimizer @dstogov
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 4f5bef65ed1f..296835e02e0d 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -31,10 +31,10 @@ body:
Please make sure that the used PHP version [is a supported version](https://www.php.net/supported-versions.php).
placeholder: |
PHP 8.5.2 (cli) (built: Jan 21 2026 17:35:28) (NTS)
- Copyright (c) The PHP Group
+ Copyright © The PHP Group and Contributors
Built by Ubuntu
- Zend Engine v4.5.2, Copyright (c) Zend Technologies
- with Zend OPcache v8.5.2, Copyright (c), by Zend Technologies
+ Zend Engine v4.5.2, Copyright © Zend by Perforce
+ with Zend OPcache v8.5.2, Copyright ©, Zend by Perforce
render: plain
validations:
required: true
diff --git a/.github/actions/freebsd/action.yml b/.github/actions/freebsd/action.yml
index 3b6d0c4e8617..197362d9f52b 100644
--- a/.github/actions/freebsd/action.yml
+++ b/.github/actions/freebsd/action.yml
@@ -46,7 +46,7 @@ runs:
pkgconf \
webp \
libavif \
- `#sqlite3` \
+ sqlite3 \
curl \
$OPCACHE_TLS_TESTS_DEPS
@@ -57,9 +57,7 @@ runs:
--enable-debug \
--enable-option-checking=fatal \
--enable-fpm \
- `#--with-pdo-sqlite` \
- --without-sqlite3 \
- --without-pdo-sqlite \
+ --with-pdo-sqlite \
--without-pear \
--with-bz2 \
--with-avif \
diff --git a/.github/labeler.yml b/.github/labeler.yml
index b9f0f36e147d..e9731352c8cc 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -20,6 +20,18 @@
- scripts/**/*
- win32/build/**/*
+"Category: CI":
+ - changed-files:
+ - any-glob-to-any-file:
+ - .circleci/*
+ - .github/actions/**/*
+ - .github/scripts/**/*
+ - .github/workflows/*
+ - .github/CODEOWNERS
+ - .github/labeler.yml
+ - .github/setup_hmailserver.php
+ - .github/matrix.php
+
"Extension: bcmath":
- changed-files:
- any-glob-to-any-file:
diff --git a/.github/matrix.php b/.github/matrix.php
index dec8c7d249c6..18c2ef1269b7 100644
--- a/.github/matrix.php
+++ b/.github/matrix.php
@@ -144,12 +144,15 @@ function select_jobs($repository, $trigger, $nightly, $labels, $php_version, $re
$jobs['SOLARIS'] = true;
}
if ($all_jobs || !$no_jobs || $test_windows) {
- $jobs['WINDOWS']['matrix'] = $all_variations
- ? ['include' => [
- ['asan' => true, 'opcache' => true, 'x64' => true, 'zts' => true],
- ['asan' => false, 'opcache' => false, 'x64' => false, 'zts' => false],
- ]]
- : ['include' => [['asan' => false, 'opcache' => true, 'x64' => true, 'zts' => true]]];
+ $matrix = [['asan' => false, 'opcache' => true, 'x64' => true, 'zts' => true]];
+ if ($all_variations) {
+ $matrix[] = ['asan' => true, 'opcache' => true, 'x64' => true, 'zts' => true];
+ $matrix[] = ['asan' => false, 'opcache' => false, 'x64' => false, 'zts' => false];
+ if (version_compare($php_version, '8.5', '>=')) {
+ $matrix[] = ['asan' => false, 'opcache' => true, 'x64' => true, 'zts' => true, 'clang' => true];
+ }
+ }
+ $jobs['WINDOWS']['matrix'] = ['include' => $matrix];
$jobs['WINDOWS']['config'] = version_compare($php_version, '8.4', '>=')
? ['vs_crt_version' => 'vs17']
: ['vs_crt_version' => 'vs16'];
diff --git a/.github/scripts/windows/build_task.bat b/.github/scripts/windows/build_task.bat
index b65479451849..1177cef3be4d 100644
--- a/.github/scripts/windows/build_task.bat
+++ b/.github/scripts/windows/build_task.bat
@@ -26,12 +26,18 @@ if %errorlevel% neq 0 exit /b 3
if "%THREAD_SAFE%" equ "0" set ADD_CONF=%ADD_CONF% --disable-zts
if "%INTRINSICS%" neq "" set ADD_CONF=%ADD_CONF% --enable-native-intrinsics=%INTRINSICS%
if "%ASAN%" equ "1" set ADD_CONF=%ADD_CONF% --enable-sanitizer --enable-debug-pack
+if "%CLANG_TOOLSET%" equ "1" set ADD_CONF=%ADD_CONF% --with-toolset=clang
rem C4018: comparison: signed/unsigned mismatch
rem C4146: unary minus operator applied to unsigned type
rem C4244: type conversion, possible loss of data
rem C4267: 'size_t' type conversion, possible loss of data
-set CFLAGS=/W3 /WX /wd4018 /wd4146 /wd4244 /wd4267
+if "%CLANG_TOOLSET%" equ "1" (
+ rem Clang is much stricter than MSVC, produces too many warnings that would fail the build with /WX
+ set CFLAGS=/W3 /wd4018 /wd4146 /wd4244 /wd4267
+) else (
+ set CFLAGS=/W3 /WX /wd4018 /wd4146 /wd4244 /wd4267
+)
cmd /c configure.bat ^
--enable-snapshot-build ^
diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml
index 9eeff1455f8f..4905dcb9ccbc 100644
--- a/.github/workflows/test-suite.yml
+++ b/.github/workflows/test-suite.yml
@@ -413,10 +413,15 @@ jobs:
with:
enableOpcache: true
jitType: tracing
- - uses: codecov/codecov-action@v5
+ - name: Generate coverage report
+ if: ${{ !cancelled() }}
+ run: make gcovr-xml
+ - uses: codecov/codecov-action@v6
if: ${{ !cancelled() }}
with:
+ disable_search: true
fail_ci_if_error: true
+ files: gcovr.xml
token: ${{ secrets.CODECOV_TOKEN }}
verbose: true
COMMUNITY:
@@ -935,7 +940,7 @@ jobs:
strategy:
fail-fast: false
matrix: ${{ fromJson(inputs.branch).jobs.WINDOWS.matrix }}
- name: "WINDOWS_${{ matrix.x64 && 'X64' || 'X86' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}${{ matrix.asan && '_ASAN' || ''}}"
+ name: "WINDOWS_${{ matrix.x64 && 'X64' || 'X86' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}${{ matrix.asan && '_ASAN' || ''}}${{ matrix.clang && '_CLANG' || ''}}"
runs-on: windows-2022
env:
PHP_BUILD_CACHE_BASE_DIR: C:\build-cache
@@ -949,6 +954,7 @@ jobs:
PARALLEL: -j2
OPCACHE: "${{ matrix.opcache && '1' || '0' }}"
ASAN: "${{ matrix.asan && '1' || '0' }}"
+ CLANG_TOOLSET: "${{ matrix.clang && '1' || '0' }}"
steps:
- name: git config
run: git config --global core.autocrlf false && git config --global core.eol lf
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 69ba4c0e4865..eafedec5eafa 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -2,15 +2,17 @@ name: Test
on:
push:
paths-ignore: &ignore_paths
+ - .circleci/**
+ - .github/CODEOWNERS
+ - .github/ISSUE_TEMPLATE/**
+ - '**/*.md'
+ - '**/*.rst'
- docs/**
+ - EXTENSIONS
+ - LICENSE
- NEWS
- UPGRADING
- UPGRADING.INTERNALS
- - '**/README.*'
- - CONTRIBUTING.md
- - CODING_STANDARDS.md
- - .cirrus.yml
- - .circleci/**
branches:
- PHP-8.2
- PHP-8.3
diff --git a/CODING_STANDARDS.md b/CODING_STANDARDS.md
index 47b76717c839..3a53d0e258ca 100644
--- a/CODING_STANDARDS.md
+++ b/CODING_STANDARDS.md
@@ -79,6 +79,16 @@ rewritten to comply with these rules.
return value for functions that perform some operation that may
succeed or fail.
+1. When throwing a `ValueError` or emitting a warning, use consistent
+ phrasing for error messages. Common patterns are:
+
+ * Type errors: `must be of type int` (use the type name, not e.g. `must be an integer`)
+ * Range/boundary: `must be between X and Y` / `must be greater than [or equal to] X` / `must be less than X` / `must be finite`
+ * String constraints: `must not contain any null bytes` / `must not be empty` / `must be a single character`
+ * Valid value: `must be a valid X` (e.g. `must be a valid encoding`, `must be a valid calendar ID`)
+ * Enum-like: `must be one of X, Y, or Z`
+ * Structural: `must have X` / `must have key X` / `must have N elements`
+
## User functions/methods naming conventions
1. Function names for user-level functions should be enclosed with in the
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 041b27f96dfb..0e13285dd735 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -37,8 +37,8 @@ implement RFCs. Please be sure to include tests as appropriate!
By submitting a pull request, you certify that you have the necessary rights
to submit the work, that the work does not violate any third-party rights
(including those of your employer, if applicable), and that you license your
-contribution under the PHP License or under another license if explicitly
-accepted by the PHP project maintainers.
+contribution under the [Modified BSD License](LICENSE) or under another license
+if explicitly accepted by the PHP project maintainers.
If you are fixing a bug, then please submit your PR against the lowest actively
supported branch of PHP that the bug affects (only green branches on
@@ -356,30 +356,21 @@ Having said that, here are the organizational rules:
`--enable-zts` switch to ensure your code handles TSRM correctly and doesn't
break for those who need that.
-Currently, we have the following branches in use:
-
-| Branch | |
-| --------- | --------- |
-| master | Active development branch for PHP 8.6, which is open for backwards incompatible changes and major internal API changes. |
-| PHP-8.5 | Is used to release the PHP 8.5.x series. This is a current stable version and is open for bugfixes only. |
-| PHP-8.4 | Is used to release the PHP 8.4.x series. This is a current stable version and is open for bugfixes only. |
-| PHP-8.3 | Is used to release the PHP 8.3.x series. This is a current stable version and is open for bugfixes only. |
-| PHP-8.2 | Is used to release the PHP 8.2.x series. This is an old stable version and is open for security fixes only. |
-| PHP-8.1 | Is used to release the PHP 8.1.x series. This is an old stable version and is open for security fixes only. |
-| PHP-8.0 | This branch is closed. |
-| PHP-7.4 | This branch is closed. |
-| PHP-7.3 | This branch is closed. |
-| PHP-7.2 | This branch is closed. |
-| PHP-7.1 | This branch is closed. |
-| PHP-7.0 | This branch is closed. |
-| PHP-5.6 | This branch is closed. |
-| PHP-5.5 | This branch is closed. |
-| PHP-5.4 | This branch is closed. |
-| PHP-5.3 | This branch is closed. |
-| PHP-5.2 | This branch is closed. |
-| PHP-5.1 | This branch is closed. |
-| PHP-4.4 | This branch is closed. |
-| PHP-X.Y.Z | These branches are used for the release managers for tagging the releases, hence they are closed to the general public. |
+The master branch is an active development branch for the newest version of PHP,
+which is open for backwards incompatible changes and major internal API changes.
+
+For PHP-X.Y branches, they are used to release the PHP X.Y.z series. Please see
+the [supported versions page](https://www.php.net/supported-versions.php) to get
+the status of each version.
+
+If a version is described as "Active support", the corresponding branch is a
+current stable version and is open for bugfixes only. If a version is described
+as "Security fixes only", the corresponding branch is an old stable version
+and is open for security fixes only. If a version is described as "End of life",
+the corresponding branch is closed.
+
+Note that PHP-X.Y.Z branches are used for the release managers for tagging the
+releases, hence they are closed to the general public.
The next few rules are more of a technical nature:
@@ -439,15 +430,13 @@ New source code files should include the following header block:
```c
/*
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Author: |
+----------------------------------------------------------------------+
diff --git a/EXTENSIONS b/EXTENSIONS
index 8da09aed5392..5a08a031e983 100644
--- a/EXTENSIONS
+++ b/EXTENSIONS
@@ -171,28 +171,28 @@ PRIMARY MAINTAINER: Christian Stocker (2003 - 2011)
Rob Richards (2003 - 2012)
Marcus Börger (2003 - 2006)
Nora Dossche (2023 - 2026)
-MAINTENANCE: Odd fixes
+MAINTENANCE: Orphan
STATUS: Working
SINCE: 5.0
-------------------------------------------------------------------------------
EXTENSION: simplexml
PRIMARY MAINTAINER: Marcus Börger (2003 - 2008)
Nora Dossche (2023 - 2026)
-MAINTENANCE: Odd fixes
+MAINTENANCE: Orphan
STATUS: Working
SINCE: 5.0
-------------------------------------------------------------------------------
EXTENSION: soap
PRIMARY MAINTAINER: Dmitry Stogov (2004 - 2018)
Nora Dossche (2024 - 2026)
-MAINTENANCE: Odd fixes
+MAINTENANCE: Orphan
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: xml
PRIMARY MAINTAINER: Thies C. Arntzen (1999 - 2002)
Rob Richards (2003 - 2013)
Nora Dossche (2023 - 2026)
-MAINTENANCE: Odd fixes
+MAINTENANCE: Orphan
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: lexbor
@@ -206,28 +206,28 @@ EXTENSION: libxml
PRIMARY MAINTAINER: Rob Richards (2003 - 2009)
Christian Stocker (2004 - 2011)
Nora Dossche (2023 - 2026)
-MAINTENANCE: Odd fixes
+MAINTENANCE: Orphan
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: xmlreader
PRIMARY MAINTAINER: Rob Richards (2004 - 2010)
Christian Stocker (2004 - 2004)
Nora Dossche (2023 - 2026)
-MAINTENANCE: Odd fixes
+MAINTENANCE: Orphan
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: xmlwriter
PRIMARY MAINTAINER: Rob Richards (2004 - 2010)
Pierre-Alain Joye (2005-2009)
Nora Dossche (2023 - 2026)
-MAINTENANCE: Odd fixes
+MAINTENANCE: Orphan
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: xsl
PRIMARY MAINTAINER: Christian Stocker (2003 - 2011)
Rob Richards (2003 - 2010)
Nora Dossche (2023 - 2026)
-MAINTENANCE: Odd fixes
+MAINTENANCE: Orphan
STATUS: Working
SINCE: 5.0
-------------------------------------------------------------------------------
@@ -496,7 +496,7 @@ PRIMARY MAINTAINER: John Coggeshall (2003 - 2006)
Ilia Alshanetsky (2003 - 2009)
Nuno Lopes (2006 - 2012)
Nora Dossche (2025 - 2026)
-MAINTENANCE: Odd fixes
+MAINTENANCE: Orphan
STATUS: Working
-------------------------------------------------------------------------------
EXTENSION: tokenizer
diff --git a/LICENSE b/LICENSE
index 16af9a6ae1e7..ee42a57fffbb 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,68 +1,27 @@
---------------------------------------------------------------------
- The PHP License, version 3.01
-Copyright (c) 1999 - 2026 The PHP Group. All rights reserved.
---------------------------------------------------------------------
+Copyright © 1999–2026, The PHP Group and Contributors.
+Copyright © 1999–2026, Zend Technologies Ltd., a subsidiary company of Perforce Software, Inc.
Redistribution and use in source and binary forms, with or without
-modification, is permitted provided that the following conditions
-are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
-
- 3. The name "PHP" must not be used to endorse or promote products
- derived from this software without prior written permission. For
- written permission, please contact group@php.net.
-
- 4. Products derived from this software may not be called "PHP", nor
- may "PHP" appear in their name, without prior written permission
- from group@php.net. You may indicate that your software works in
- conjunction with PHP by saying "Foo for PHP" instead of calling
- it "PHP Foo" or "phpfoo"
-
- 5. The PHP Group may publish revised and/or new versions of the
- license from time to time. Each version will be given a
- distinguishing version number.
- Once covered code has been published under a particular version
- of the license, you may always continue to use it under the terms
- of that version. You may also choose to use such covered code
- under the terms of any subsequent version of the license
- published by the PHP Group. No one other than the PHP Group has
- the right to modify the terms applicable to covered code created
- under this License.
-
- 6. Redistributions of any form whatsoever must retain the following
- acknowledgment:
- "This product includes PHP software, freely available from
- ".
-
-THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
-ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
-DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
-INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
-OF THE POSSIBILITY OF SUCH DAMAGE.
-
---------------------------------------------------------------------
-
-This software consists of voluntary contributions made by many
-individuals on behalf of the PHP Group.
-
-The PHP Group can be contacted via Email at group@php.net.
-
-For more information on the PHP Group and the PHP project,
-please see .
-
-PHP includes the Zend Engine, freely available at
-.
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/NEWS b/NEWS
index 44f53eb99c7a..22762f98c2ca 100644
--- a/NEWS
+++ b/NEWS
@@ -26,12 +26,26 @@ PHP NEWS
- DOM:
. Removed LIBXML_XINCLUDE from valid options for XMLDocument,
as it was a no-op. (ndossche)
+ . Readonly DOM properties are now declared with asymmetric visibility
+ (public private(set)). ReflectionProperty::isWritable() reports them
+ correctly, and external writes raise "Cannot modify private(set)
+ property" instead of the previous readonly modification error.
+ (David Carlier)
- Fileinfo:
. Fixed bug GH-20679 (finfo_file() doesn't work on remote resources).
(ndossche)
. Fixed bug #66095 (Hide libmagic dynamic symbols). (orlitzky)
+- GD:
+ . imagesetstyle()/imagefilter()/imagecrop() check array argument entries
+ types. (David Carlier)
+
+- GMP:
+ . gmp_fact() reject values larger than unsigned long. (David Carlier)
+ . gmp_pow/binomial/root/rootrem and shift/pow operators reject values
+ larger than unsigned long. (David Carlier)
+
- Hash:
. Upgrade xxHash to 0.8.2. (timwolla)
@@ -64,6 +78,9 @@ PHP NEWS
. Fixed bug GH-21223; mb_guess_encoding no longer crashes when passed huge
list of candidate encodings (with 200,000+ entries). (Jordi Kroon)
+- Mysqli:
+ . Added mysqli_quote_string() and mysqli::quote_string(). (Kamil Tekiela)
+
- Opcache:
. Fixed bug GH-20051 (apache2 shutdowns when restart is requested during
preloading). (Arnaud, welcomycozyhom)
@@ -100,6 +117,7 @@ PHP NEWS
(ilutov)
. Fixed bug GH-21362 (ReflectionMethod::invoke/invokeArgs() did not verify
Closure instance identity for Closure::__invoke()). (Ilia Alshanetsky)
+ . Added ReflectionParameter::getDocComment(). (chschneider)
- Session:
. Fixed bug 71162 (updateTimestamp never called when session data is empty).
@@ -125,6 +143,8 @@ PHP NEWS
- SPL:
. DirectoryIterator key can now work better with filesystem supporting larger
directory indexing. (David Carlier)
+ . Fix bugs GH-8561, GH-8562, GH-8563, and GH-8564 (Fixing various
+ SplFileObject iterator desync bugs). (iliaal)
- Sqlite3:
. Fix NUL byte truncation in sqlite3 TEXT column handling. (ndossche)
@@ -141,6 +161,17 @@ PHP NEWS
. Fixed bug GH-13204 (glob() fails if square bracket is in current directory).
(ndossche)
. Add array size maximum to array_diff(). (ndossche)
+ . Add enum SortDirection. (timwolla)
+ . pathinfo() raises a ValueError with an invalid $flags argument.
+ (David Carlier)
+ . Passing an invalid flag value to the second argument of scandir() will now
+ throw a ValueError. (alexandre-daubois)
+ . array_change_key_case() now raises a ValueError when an invalid $case
+ argument value is passed. (Girgias)
+ . linkinfo() now raises a ValueError when the argument is an empty string.
+ (Weilin Du)
+ . getenv() and putenv() now raises a ValueError when the first argument
+ contains null bytes. (Weilin Du)
- Streams:
. Added so_keepalive, tcp_keepidle, tcp_keepintvl and tcp_keepcnt stream
diff --git a/README.md b/README.md
index 545baa720967..3f4e0534ede2 100644
--- a/README.md
+++ b/README.md
@@ -11,8 +11,10 @@
PHP is a popular general-purpose scripting language that is especially suited to
web development. Fast, flexible and pragmatic, PHP powers everything from your
-blog to the most popular websites in the world. PHP is distributed under the
-[PHP License v3.01](LICENSE).
+blog to the most popular websites in the world.
+
+PHP is distributed under the [Modified BSD License](LICENSE)
+(SPDX-License-Identifier: `BSD-3-Clause`).
[](https://github.com/php/php-src/actions/workflows/test.yml)
[](https://issues.oss-fuzz.com/issues?q=project:php)
diff --git a/TSRM/TSRM.h b/TSRM/TSRM.h
index 80d6cbad0443..ea13552c8374 100644
--- a/TSRM/TSRM.h
+++ b/TSRM/TSRM.h
@@ -175,9 +175,14 @@ TSRM_API bool tsrm_is_managed_thread(void);
#define TSRMG_BULK_STATIC(id, type) ((type) (*((void ***) TSRMLS_CACHE))[TSRM_UNSHUFFLE_RSRC_ID(id)])
#define TSRMG_FAST_STATIC(offset, type, element) (TSRMG_FAST_BULK_STATIC(offset, type)->element)
#define TSRMG_FAST_BULK_STATIC(offset, type) ((type) (((char*) TSRMLS_CACHE)+(offset)))
+#ifdef __cplusplus
+#define TSRMLS_MAIN_CACHE_EXTERN() extern "C" { extern TSRM_TLS void *TSRMLS_CACHE TSRM_TLS_MODEL_ATTR; }
+#define TSRMLS_CACHE_EXTERN() extern "C" { extern TSRM_TLS void *TSRMLS_CACHE; }
+#else
#define TSRMLS_MAIN_CACHE_EXTERN() extern TSRM_TLS void *TSRMLS_CACHE TSRM_TLS_MODEL_ATTR;
-#define TSRMLS_MAIN_CACHE_DEFINE() TSRM_TLS void *TSRMLS_CACHE TSRM_TLS_MODEL_ATTR = NULL;
#define TSRMLS_CACHE_EXTERN() extern TSRM_TLS void *TSRMLS_CACHE;
+#endif
+#define TSRMLS_MAIN_CACHE_DEFINE() TSRM_TLS void *TSRMLS_CACHE TSRM_TLS_MODEL_ATTR = NULL;
#define TSRMLS_CACHE_DEFINE() TSRM_TLS void *TSRMLS_CACHE = NULL;
#define TSRMLS_CACHE_UPDATE() TSRMLS_CACHE = tsrm_get_ls_cache()
#define TSRMLS_CACHE _tsrm_ls_cache
diff --git a/TSRM/tsrm_win32.c b/TSRM/tsrm_win32.c
index 4c8fc9d19aa9..90317ab64b19 100644
--- a/TSRM/tsrm_win32.c
+++ b/TSRM/tsrm_win32.c
@@ -1,14 +1,12 @@
/*
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Daniel Beulshausen |
+----------------------------------------------------------------------+
diff --git a/TSRM/tsrm_win32.h b/TSRM/tsrm_win32.h
index c5bdc492be1b..9c16bd7c654b 100644
--- a/TSRM/tsrm_win32.h
+++ b/TSRM/tsrm_win32.h
@@ -1,14 +1,12 @@
/*
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Daniel Beulshausen |
+----------------------------------------------------------------------+
diff --git a/UPGRADING b/UPGRADING
index 8c312f1814a0..869e265af8a2 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -19,14 +19,39 @@ PHP 8.6 UPGRADE NOTES
1. Backward Incompatible Changes
========================================
+- DOM:
+ . Properties previously documented as @readonly (e.g. DOMNode::$nodeType,
+ DOMDocument::$xmlEncoding, DOMEntity::$actualEncoding, ::$encoding,
+ ::$version) are now declared with asymmetric visibility
+ (public private(set)). Attempts to write to them from outside the
+ class now raise "Cannot modify private(set) property ::$
+ from global scope" instead of the prior readonly modification error.
+ ReflectionProperty::isWritable() also reports these properties
+ accurately.
+
+- GD:
+ . imagesetstyle(), imagefilter() and imagecrop() filter their
+ array arguments types/values and raise a TypeError/ValueError
+ accordingly.
+
+- PCNTL:
+ . pcntl_alarm() now raises a ValueError if the seconds argument is
+ lower than zero or greater than platform's UINT_MAX.
+
- PCRE:
. preg_grep() now returns false instead of a partial array when a PCRE
execution error occurs (e.g. malformed UTF-8 input with the /u modifier).
This is consistent with other preg_* functions.
- Phar:
- . Invalid values now throw in Phar::mungServer() instead of being silently
- ignored.
+ . Phar::mungServer() now raises a ValueError when an invalid
+ argument value is passed instead of being silently ignored.
+
+- Posix:
+ . posix_access() now raises a ValueError when an invalid $flags
+ argument value is passed.
+ . posix_mkfifo() now raises a ValueError when an invalid $permissions
+ argument value is passed.
- Session:
. A ValueError is not thrown if $name is a string containing null bytes in
@@ -44,11 +69,37 @@ PHP 8.6 UPGRADE NOTES
with empty data (e.g. to destroy the session) should implement the same
logic in their updateTimestamp() method.
+- SPL:
+ . SplFileObject::next() now advances the stream when no prior current()
+ call has cached a line. A subsequent current() call returns the new
+ line rather than the previous one.
+ . SplFileObject::fgets() no longer caches the returned line for
+ subsequent current() calls. current() now re-reads from the current
+ stream position instead of returning the line fgets() just returned.
+ . SplFileObject::next() past EOF no longer increments key() without
+ bound. SplFileObject::seek() past EOF now produces the same key()
+ value as SplTempFileObject; the two previously returned different
+ values.
+
- Standard:
- . Invalid mode values now throw in array_filter() instead of being silently
- defaulted to 0.
. Form feed (\f) is now added in the default trimmed characters of trim(),
rtrim() and ltrim(). RFC: https://wiki.php.net/rfc/trim_form_feed
+ . array_filter() now raises a ValueError when an invalid $mode
+ argument value is passed.
+ . array_change_key_case() now raises a ValueError when an invalid $case
+ argument value is passed.
+ . getenv() and putenv() now raises a ValueError when the first argument
+ contains null bytes.
+ . linkinfo() now raises a ValueError when the $path argument is empty.
+ . pathinfo() now raises a ValueError when an invalid $flag
+ argument value is passed.
+ . scandir() now raises a ValueError when an invalid $sorting_order
+ argument value is passed.
+
+- Zip:
+ . ZipArchive::extractTo now raises a TypeError for the
+ files argument if one or more of the entries is not
+ a string.
========================================
2. New Features
@@ -103,6 +154,17 @@ PHP 8.6 UPGRADE NOTES
5. Changed Functions
========================================
+- GMP:
+ . gmp_fact() now throws a ValueError() if $num does not fit into
+ a unsigned long.
+ . gmp_pow(), gmp_binomial(), gmp_root() and gmp_rootrem() now throw a
+ ValueError if their second argument does not fit into an unsigned long.
+ . The shift (<<, >>) and exponentiation (**) operators on GMP objects
+ now throw a ValueError if the right operand does not fit into an
+ unsigned long.
+ . gmp_powm() modulo-by-zero now raises a DivisionByZeroError whose
+ message includes the function name and argument index ($modulus).
+
- mysqli:
. The return structure of mysqli_get_charset() no longer contains
the undocumented "comment" element. The value of "charsetnr" is
@@ -113,29 +175,14 @@ PHP 8.6 UPGRADE NOTES
. Output of openssl_x509_parse() contains criticalExtensions listing all
critical certificate extensions.
-- PCNTL:
- . pcntl_alarm() now throws a ValueError if the seconds argument is
- lower than zero or greater than platform's UINT_MAX.
-
- Phar:
. Phar::mungServer() now supports reference values.
-- Posix:
- . posix_access() now throws a ValueError exception if the flags
- argument is invalid.
- . posix_mkfifo() now throws a ValueError exception if the permissions
- argument is invalid.
-
- Sockets:
. socket_addrinfo_lookup() now has an additional optional argument $error
when not null, and on failure, gives the error code (one of the EAI_*
constants).
-- Zip:
- . ZipArchive::extractTo now raises a TypeError for the
- files argument if one or more of the entries is not
- a string.
-
========================================
6. New Functions
========================================
@@ -144,11 +191,17 @@ PHP 8.6 UPGRADE NOTES
. ReflectionConstant::inNamespace()
. Added ReflectionProperty::isReadable() and ReflectionProperty::isWritable().
RFC: https://wiki.php.net/rfc/isreadable-iswriteable
+ . Added ReflectionParameter::getDocComment().
+ RFC: https://wiki.php.net/rfc/parameter-doccomments
- Intl:
. `grapheme_strrev()` returns strrev for grapheme cluster unit.
RFC: https://wiki.php.net/rfc/grapheme_strrev
+- mysqli:
+ . Added `mysqli::quote_string()` and `mysqli_quote_string()`.
+ RFC: https://wiki.php.net/rfc/mysqli_quote_string
+
- Standard:
. `clamp()` returns the given value if in range, else return the nearest
bound.
@@ -161,6 +214,10 @@ PHP 8.6 UPGRADE NOTES
7. New Classes and Interfaces
========================================
+- Standard:
+ . enum SortDirection
+ RFC: https://wiki.php.net/rfc/sort_direction_enum
+
========================================
8. Removed Extensions and SAPIs
========================================
@@ -201,12 +258,19 @@ PHP 8.6 UPGRADE NOTES
. EAI_IDN_ENCODE.
- Standard
- . ARRAY_FILTER_USE_KEY.
+ . ARRAY_FILTER_USE_VALUE.
========================================
11. Changes to INI File Handling
========================================
+- Mbstring:
+ . The mbstring.detect_order INI directive now updates the internal detection
+ order when changed at runtime via ini_set(). Previously, runtime changes
+ using ini_set() did not take effect for mb_detect_order(). Setting the
+ directive to NULL or an empty string at runtime now leaves the previously
+ configured detection order unchanged.
+
- Mysqli:
. mysqli.default_port now checks the validity of the value which should be
between 0 and 65535 included.
@@ -216,13 +280,6 @@ PHP 8.6 UPGRADE NOTES
When used along with ZEND_JIT_DEBUG_TRACE_EXIT_INFO, the source of exit
points is printed in exit info output, in debug builds.
-- Mbstring:
- . The mbstring.detect_order INI directive now updates the internal detection
- order when changed at runtime via ini_set(). Previously, runtime changes
- using ini_set() did not take effect for mb_detect_order(). Setting the
- directive to NULL or an empty string at runtime now leaves the previously
- configured detection order unchanged.
-
========================================
12. Windows Support
========================================
diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS
index 1072d822ee49..1d53df7e4a33 100644
--- a/UPGRADING.INTERNALS
+++ b/UPGRADING.INTERNALS
@@ -83,6 +83,14 @@ PHP 8.6 INTERNALS UPGRADE NOTES
. The INI_ORIG_{INT|STR|FLT|BOOL}() macros have been removed as they are
unused. If this behaviour is required fall back to the zend_ini_*
functions.
+ . The unused ZEND_AST_PARENT_PROPERTY_HOOK_CALL has been removed.
+ . ZEND_AST_METHOD_REFERENCE has been renamed to
+ ZEND_AST_TRAIT_METHOD_REFERENCE.
+ . The EMPTY_SWITCH_DEFAULT_CASE() macro has been removed. Use
+ default: ZEND_UNREACHABLE(); instead.
+ . Functions using zend_forbid_dynamic_call() *must* be flagged with
+ ZEND_ACC2_FORBID_DYN_CALLS (@forbid-dynamic-calls in stubs). In debug
+ builds, failing to include that flag will lead to assertion failures.
========================
2. Build system changes
@@ -128,6 +136,7 @@ PHP 8.6 INTERNALS UPGRADE NOTES
. Dropped session_options parameter from all methods in mysqlnd_auth.
The same information is present in conn->options and should be used
instead.
+ . Removed charsets plugin.
- ext/session:
. php_session_flush() now returns a bool rather than a zend_result.
diff --git a/Zend/LICENSE b/Zend/LICENSE
deleted file mode 100644
index 51f5cccde950..000000000000
--- a/Zend/LICENSE
+++ /dev/null
@@ -1,56 +0,0 @@
---------------------------------------------------------------------
- The Zend Engine License, Version 2.00
-Copyright (c) 1999-2006 Zend Technologies Ltd. All rights reserved.
---------------------------------------------------------------------
-
-Redistribution and use in source and binary forms, with or without
-modification, is permitted provided that the following conditions
-are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
-
- 3. The names "Zend" and "Zend Engine" must not be used to endorse
- or promote products derived from this software without prior
- permission from Zend Technologies Ltd. For written permission,
- please contact license@zend.com.
-
- 4. Zend Technologies Ltd. may publish revised and/or new versions
- of the license from time to time. Each version will be given a
- distinguishing version number.
- Once covered code has been published under a particular version
- of the license, you may always continue to use it under the
- terms of that version. You may also choose to use such covered
- code under the terms of any subsequent version of the license
- published by Zend Technologies Ltd. No one other than Zend
- Technologies Ltd. has the right to modify the terms applicable
- to covered code created under this License.
-
- 5. Redistributions of any form whatsoever must retain the following
- acknowledgment:
- "This product includes the Zend Engine, freely available at
- http://www.zend.com"
-
- 6. All advertising materials mentioning features or use of this
- software must display the following acknowledgment:
- "The Zend Engine is freely available at http://www.zend.com"
-
-THIS SOFTWARE IS PROVIDED BY ZEND TECHNOLOGIES LTD. ``AS IS'' AND
-ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ZEND
-TECHNOLOGIES LTD. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
---------------------------------------------------------------------
diff --git a/Zend/Optimizer/block_pass.c b/Zend/Optimizer/block_pass.c
index 61a69dae51e1..c85b444640a8 100644
--- a/Zend/Optimizer/block_pass.c
+++ b/Zend/Optimizer/block_pass.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans |
| Zeev Suraski |
diff --git a/Zend/Optimizer/compact_literals.c b/Zend/Optimizer/compact_literals.c
index 447a034530e1..a4ecb19c85ef 100644
--- a/Zend/Optimizer/compact_literals.c
+++ b/Zend/Optimizer/compact_literals.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
| Xinchen Hui |
@@ -735,6 +733,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
case ZEND_SEND_VAR_NO_REF_EX:
case ZEND_SEND_REF:
case ZEND_SEND_FUNC_ARG:
+ case ZEND_SEND_PLACEHOLDER:
case ZEND_CHECK_FUNC_ARG:
if (opline->op2_type == IS_CONST) {
opline->result.num = cache_size;
@@ -747,6 +746,10 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
cache_size += sizeof(void *);
}
break;
+ case ZEND_CALLABLE_CONVERT_PARTIAL:
+ opline->op1.num = cache_size;
+ cache_size += 2 * sizeof(void *);
+ break;
}
opline++;
}
diff --git a/Zend/Optimizer/compact_vars.c b/Zend/Optimizer/compact_vars.c
index 9898714a17c5..b4a861d3595c 100644
--- a/Zend/Optimizer/compact_vars.c
+++ b/Zend/Optimizer/compact_vars.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine, Removing unused variables |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Nikita Popov |
+----------------------------------------------------------------------+
diff --git a/Zend/Optimizer/dce.c b/Zend/Optimizer/dce.c
index a529f5a1944a..0780ac190cdd 100644
--- a/Zend/Optimizer/dce.c
+++ b/Zend/Optimizer/dce.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine, DCE - Dead Code Elimination |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Nikita Popov |
| Dmitry Stogov |
diff --git a/Zend/Optimizer/dfa_pass.c b/Zend/Optimizer/dfa_pass.c
index cfc6b27b3d21..77dc322fbdec 100644
--- a/Zend/Optimizer/dfa_pass.c
+++ b/Zend/Optimizer/dfa_pass.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
+----------------------------------------------------------------------+
diff --git a/Zend/Optimizer/escape_analysis.c b/Zend/Optimizer/escape_analysis.c
index 5ace81f35220..8dbd6855d68d 100644
--- a/Zend/Optimizer/escape_analysis.c
+++ b/Zend/Optimizer/escape_analysis.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend OPcache, Escape Analysis |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
+----------------------------------------------------------------------+
diff --git a/Zend/Optimizer/nop_removal.c b/Zend/Optimizer/nop_removal.c
index 7de3919ee8cb..0a6a04fc4a9b 100644
--- a/Zend/Optimizer/nop_removal.c
+++ b/Zend/Optimizer/nop_removal.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans |
| Zeev Suraski |
diff --git a/Zend/Optimizer/optimize_func_calls.c b/Zend/Optimizer/optimize_func_calls.c
index 62b50464e87b..05cdce4fc4cf 100644
--- a/Zend/Optimizer/optimize_func_calls.c
+++ b/Zend/Optimizer/optimize_func_calls.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
| Xinchen Hui |
@@ -193,6 +191,7 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
case ZEND_DO_UCALL:
case ZEND_DO_FCALL_BY_NAME:
case ZEND_CALLABLE_CONVERT:
+ case ZEND_CALLABLE_CONVERT_PARTIAL:
call--;
if (call_stack[call].func && call_stack[call].opline) {
zend_op *fcall = call_stack[call].opline;
@@ -225,13 +224,14 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
* At this point we also know whether or not the result of
* the DO opcode is used, allowing to optimize calls to
* ZEND_ACC_NODISCARD functions. */
- if (opline->opcode != ZEND_CALLABLE_CONVERT) {
+ if (opline->opcode != ZEND_CALLABLE_CONVERT && opline->opcode != ZEND_CALLABLE_CONVERT_PARTIAL) {
opline->opcode = zend_get_call_op(fcall, call_stack[call].func, !RESULT_UNUSED(opline));
}
if ((ZEND_OPTIMIZER_PASS_16 & ctx->optimization_level)
&& call_stack[call].try_inline
- && opline->opcode != ZEND_CALLABLE_CONVERT) {
+ && opline->opcode != ZEND_CALLABLE_CONVERT
+ && opline->opcode != ZEND_CALLABLE_CONVERT_PARTIAL) {
zend_try_inline_call(op_array, fcall, opline, call_stack[call].func);
}
}
diff --git a/Zend/Optimizer/optimize_temp_vars_5.c b/Zend/Optimizer/optimize_temp_vars_5.c
index de0b189d5dca..6a5c99f4755b 100644
--- a/Zend/Optimizer/optimize_temp_vars_5.c
+++ b/Zend/Optimizer/optimize_temp_vars_5.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans |
| Zeev Suraski |
diff --git a/Zend/Optimizer/pass1.c b/Zend/Optimizer/pass1.c
index 4be966c25d89..962bdb6e4be3 100644
--- a/Zend/Optimizer/pass1.c
+++ b/Zend/Optimizer/pass1.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans |
| Zeev Suraski |
diff --git a/Zend/Optimizer/pass3.c b/Zend/Optimizer/pass3.c
index 5c31de7bc49c..2d2a44685226 100644
--- a/Zend/Optimizer/pass3.c
+++ b/Zend/Optimizer/pass3.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans |
| Zeev Suraski |
diff --git a/Zend/Optimizer/sccp.c b/Zend/Optimizer/sccp.c
index 1457e7467cf7..ba94e9b7b91f 100644
--- a/Zend/Optimizer/sccp.c
+++ b/Zend/Optimizer/sccp.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine, SCCP - Sparse Conditional Constant Propagation |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Nikita Popov |
| Dmitry Stogov |
@@ -1596,7 +1594,7 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
case ZEND_SHORT_CIRCUITING_CHAIN_EMPTY:
ZVAL_TRUE(&zv);
break;
- EMPTY_SWITCH_DEFAULT_CASE()
+ default: ZEND_UNREACHABLE();
}
SET_RESULT(result, &zv);
break;
diff --git a/Zend/Optimizer/scdf.c b/Zend/Optimizer/scdf.c
index cf7b80bc8665..31f40a7ed9f9 100644
--- a/Zend/Optimizer/scdf.c
+++ b/Zend/Optimizer/scdf.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine, Sparse Conditional Data Flow Propagation Framework |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Nikita Popov |
+----------------------------------------------------------------------+
diff --git a/Zend/Optimizer/scdf.h b/Zend/Optimizer/scdf.h
index c3f1d8e885c2..d7bee4b73816 100644
--- a/Zend/Optimizer/scdf.h
+++ b/Zend/Optimizer/scdf.h
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine, Call Graph |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Nikita Popov |
+----------------------------------------------------------------------+
diff --git a/Zend/Optimizer/ssa_integrity.c b/Zend/Optimizer/ssa_integrity.c
index 4c720714ca58..34a2b3a9ef64 100644
--- a/Zend/Optimizer/ssa_integrity.c
+++ b/Zend/Optimizer/ssa_integrity.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine, SSA validation |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Nikita Popov |
+----------------------------------------------------------------------+
diff --git a/Zend/Optimizer/zend_call_graph.c b/Zend/Optimizer/zend_call_graph.c
index 884b481aceb8..b67f57cf041d 100644
--- a/Zend/Optimizer/zend_call_graph.c
+++ b/Zend/Optimizer/zend_call_graph.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine, Call Graph |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
+----------------------------------------------------------------------+
@@ -126,6 +124,7 @@ ZEND_API void zend_analyze_calls(zend_arena **arena, zend_script *script, uint32
case ZEND_DO_UCALL:
case ZEND_DO_FCALL_BY_NAME:
case ZEND_CALLABLE_CONVERT:
+ case ZEND_CALLABLE_CONVERT_PARTIAL:
func_info->flags |= ZEND_FUNC_HAS_CALLS;
if (call_info) {
call_info->caller_call_opline = opline;
@@ -142,6 +141,7 @@ ZEND_API void zend_analyze_calls(zend_arena **arena, zend_script *script, uint32
case ZEND_SEND_VAR_NO_REF:
case ZEND_SEND_VAR_NO_REF_EX:
case ZEND_SEND_USER:
+ case ZEND_SEND_PLACEHOLDER:
if (call_info) {
if (opline->op2_type == IS_CONST) {
call_info->named_args = true;
diff --git a/Zend/Optimizer/zend_call_graph.h b/Zend/Optimizer/zend_call_graph.h
index 8810dc1a560e..57c6bdffe998 100644
--- a/Zend/Optimizer/zend_call_graph.h
+++ b/Zend/Optimizer/zend_call_graph.h
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine, Call Graph |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
+----------------------------------------------------------------------+
diff --git a/Zend/Optimizer/zend_cfg.c b/Zend/Optimizer/zend_cfg.c
index bdb3a0570539..837515169d70 100644
--- a/Zend/Optimizer/zend_cfg.c
+++ b/Zend/Optimizer/zend_cfg.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine, CFG - Control Flow Graph |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
+----------------------------------------------------------------------+
diff --git a/Zend/Optimizer/zend_cfg.h b/Zend/Optimizer/zend_cfg.h
index 8096565e8038..3ed635ecdedc 100644
--- a/Zend/Optimizer/zend_cfg.h
+++ b/Zend/Optimizer/zend_cfg.h
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine, CFG - Control Flow Graph |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
+----------------------------------------------------------------------+
diff --git a/Zend/Optimizer/zend_dfg.c b/Zend/Optimizer/zend_dfg.c
index b6c0e3d801bb..72e15693a844 100644
--- a/Zend/Optimizer/zend_dfg.c
+++ b/Zend/Optimizer/zend_dfg.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine, DFG - Data Flow Graph |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
+----------------------------------------------------------------------+
diff --git a/Zend/Optimizer/zend_dfg.h b/Zend/Optimizer/zend_dfg.h
index af3d761ba29f..464ea6bb2ebe 100644
--- a/Zend/Optimizer/zend_dfg.h
+++ b/Zend/Optimizer/zend_dfg.h
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine, DFG - Data Flow Graph |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
+----------------------------------------------------------------------+
diff --git a/Zend/Optimizer/zend_dump.c b/Zend/Optimizer/zend_dump.c
index 56a2f65d6fb2..c6cc5193b2dc 100644
--- a/Zend/Optimizer/zend_dump.c
+++ b/Zend/Optimizer/zend_dump.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine, Bytecode Visualisation |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
+----------------------------------------------------------------------+
diff --git a/Zend/Optimizer/zend_dump.h b/Zend/Optimizer/zend_dump.h
index 671f7c064fb2..45740d9609cb 100644
--- a/Zend/Optimizer/zend_dump.h
+++ b/Zend/Optimizer/zend_dump.h
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine, Bytecode Visualisation |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
+----------------------------------------------------------------------+
diff --git a/Zend/Optimizer/zend_func_info.c b/Zend/Optimizer/zend_func_info.c
index cec52f7e9860..185fcc40be67 100644
--- a/Zend/Optimizer/zend_func_info.c
+++ b/Zend/Optimizer/zend_func_info.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine, Func Info |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
| Xinchen Hui |
diff --git a/Zend/Optimizer/zend_func_info.h b/Zend/Optimizer/zend_func_info.h
index db00d843ee10..6b5b51cac58b 100644
--- a/Zend/Optimizer/zend_func_info.h
+++ b/Zend/Optimizer/zend_func_info.h
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine, Func Info |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
+----------------------------------------------------------------------+
diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c
index c19d864f1bd0..2e6cc70ec254 100644
--- a/Zend/Optimizer/zend_inference.c
+++ b/Zend/Optimizer/zend_inference.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine, e-SSA based Type & Range Inference |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
+----------------------------------------------------------------------+
@@ -1063,7 +1061,7 @@ static bool zend_inference_calc_binary_op_range(
case ZEND_BW_XOR:
// TODO
break;
- EMPTY_SWITCH_DEFAULT_CASE()
+ default: ZEND_UNREACHABLE();
}
return 0;
}
@@ -2350,7 +2348,7 @@ static uint32_t binary_op_result_type(
/* TODO: +MAY_BE_OBJECT ??? */
tmp = MAY_BE_STRING | MAY_BE_RC1 | MAY_BE_RCN;
break;
- EMPTY_SWITCH_DEFAULT_CASE()
+ default: ZEND_UNREACHABLE();
}
return tmp;
}
@@ -3708,7 +3706,7 @@ static zend_always_inline zend_result _zend_update_type_info(
case ZEND_FREE:
/* This may happen if the using opcode is DCEd. */
break;
- EMPTY_SWITCH_DEFAULT_CASE()
+ default: ZEND_UNREACHABLE();
}
j = zend_ssa_next_use(ssa->ops, ssa_op->result_def, j);
if (j >= 0) {
@@ -3905,6 +3903,7 @@ static zend_always_inline zend_result _zend_update_type_info(
}
break;
case ZEND_CALLABLE_CONVERT:
+ case ZEND_CALLABLE_CONVERT_PARTIAL:
UPDATE_SSA_TYPE(MAY_BE_OBJECT | MAY_BE_RC1 | MAY_BE_RCN, ssa_op->result_def);
UPDATE_SSA_OBJ_TYPE(zend_ce_closure, /* is_instanceof */ false, ssa_op->result_def);
break;
@@ -5294,10 +5293,10 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op
return (t1 & MAY_BE_OBJECT);
case IS_OBJECT:
return 0;
- EMPTY_SWITCH_DEFAULT_CASE()
+ default: ZEND_UNREACHABLE();
}
/* GCC is getting confused here for the Wimplicit-fallthrough warning with
- * EMPTY_SWITCH_DEFAULT_CASE() macro */
+ * default: ZEND_UNREACHABLE(); macro */
return 0;
case ZEND_ARRAY_KEY_EXISTS:
if ((t2 & MAY_BE_ANY) != MAY_BE_ARRAY) {
diff --git a/Zend/Optimizer/zend_inference.h b/Zend/Optimizer/zend_inference.h
index 1b626fa2ee22..e6b4207c7494 100644
--- a/Zend/Optimizer/zend_inference.h
+++ b/Zend/Optimizer/zend_inference.h
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine, e-SSA based Type & Range Inference |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
+----------------------------------------------------------------------+
diff --git a/Zend/Optimizer/zend_optimizer.c b/Zend/Optimizer/zend_optimizer.c
index f8cbefdaaf2b..59a87823eb56 100644
--- a/Zend/Optimizer/zend_optimizer.c
+++ b/Zend/Optimizer/zend_optimizer.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans |
| Zeev Suraski |
diff --git a/Zend/Optimizer/zend_optimizer.h b/Zend/Optimizer/zend_optimizer.h
index 43a0f60a2321..d2847c92869c 100644
--- a/Zend/Optimizer/zend_optimizer.h
+++ b/Zend/Optimizer/zend_optimizer.h
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans |
| Zeev Suraski |
diff --git a/Zend/Optimizer/zend_optimizer_internal.h b/Zend/Optimizer/zend_optimizer_internal.h
index 869275811e3d..d01df56260bc 100644
--- a/Zend/Optimizer/zend_optimizer_internal.h
+++ b/Zend/Optimizer/zend_optimizer_internal.h
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans |
| Zeev Suraski |
diff --git a/Zend/Optimizer/zend_ssa.c b/Zend/Optimizer/zend_ssa.c
index e30159f8f3c6..fa2901b89421 100644
--- a/Zend/Optimizer/zend_ssa.c
+++ b/Zend/Optimizer/zend_ssa.c
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine, SSA - Static Single Assignment Form |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
| Nikita Popov |
diff --git a/Zend/Optimizer/zend_ssa.h b/Zend/Optimizer/zend_ssa.h
index 4f591618750f..ee9faf9bfd23 100644
--- a/Zend/Optimizer/zend_ssa.h
+++ b/Zend/Optimizer/zend_ssa.h
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine, SSA - Static Single Assignment Form |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
+----------------------------------------------------------------------+
diff --git a/Zend/Optimizer/zend_worklist.h b/Zend/Optimizer/zend_worklist.h
index 85e7b111d5c9..ea03048e9756 100644
--- a/Zend/Optimizer/zend_worklist.h
+++ b/Zend/Optimizer/zend_worklist.h
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Andy Wingo |
+----------------------------------------------------------------------+
diff --git a/Zend/tests/enum/gh21760.phpt b/Zend/tests/enum/gh21760.phpt
new file mode 100644
index 000000000000..0835e3ca937d
--- /dev/null
+++ b/Zend/tests/enum/gh21760.phpt
@@ -0,0 +1,19 @@
+--TEST--
+GH-21760 (Trait with class constant name conflict against enum case causes SEGV)
+--FILE--
+
+--EXPECTF--
+Fatal error: Cannot use trait X, because X::Up conflicts with enum case Direction::Up in %s on line %d
diff --git a/Zend/tests/first_class_callable/first_class_callable_non_unary_error.phpt b/Zend/tests/first_class_callable/first_class_callable_non_unary_error.phpt
deleted file mode 100644
index 74e36a9ad0df..000000000000
--- a/Zend/tests/first_class_callable/first_class_callable_non_unary_error.phpt
+++ /dev/null
@@ -1,10 +0,0 @@
---TEST--
-First class callable error: more than one argument
---FILE--
-
---EXPECTF--
-Fatal error: Cannot create a Closure for call expression with more than one argument, or non-variadic placeholders in %s on line %d
diff --git a/Zend/tests/first_class_callable/first_class_callable_non_variadic_error.phpt b/Zend/tests/first_class_callable/first_class_callable_non_variadic_error.phpt
deleted file mode 100644
index efbd13b7593b..000000000000
--- a/Zend/tests/first_class_callable/first_class_callable_non_variadic_error.phpt
+++ /dev/null
@@ -1,10 +0,0 @@
---TEST--
-First class callable error: non-variadic placeholder
---FILE--
-
---EXPECTF--
-Fatal error: Cannot create a Closure for call expression with more than one argument, or non-variadic placeholders in %s on line %d
diff --git a/Zend/tests/gh16799.phpt b/Zend/tests/gh16799.phpt
index ce1dbd5b1655..d31d1a5705c6 100644
--- a/Zend/tests/gh16799.phpt
+++ b/Zend/tests/gh16799.phpt
@@ -15,7 +15,12 @@ Test::test();
--EXPECTF--
Fatal error: Uncaught Exception: Use of "static" in callables is deprecated in %s:%d
Stack trace:
-#0 %s(%d): {closure:%s:%d}(8192, 'Use of "static"...', %s, %d)
+#0 %s(%d): {closure:%s}(8192, 'Use of "static"%s', '%s', %d)
#1 %s(%d): Test::test()
#2 {main}
+
+Next TypeError: call_user_func(): Argument #1 ($callback) must be a valid callback, (null) in %s:%d
+Stack trace:
+#0 %s(%d): Test::test()
+#1 {main}
thrown in %s on line %d
diff --git a/Zend/tests/gh21504.inc b/Zend/tests/gh21504.inc
new file mode 100644
index 000000000000..71dc5c2e61f6
--- /dev/null
+++ b/Zend/tests/gh21504.inc
@@ -0,0 +1,3 @@
+ var_dump(...);
diff --git a/Zend/tests/gh21504.phpt b/Zend/tests/gh21504.phpt
new file mode 100644
index 000000000000..5fd9eaff91ab
--- /dev/null
+++ b/Zend/tests/gh21504.phpt
@@ -0,0 +1,12 @@
+--TEST--
+GH-21504: Incorrect RC-handling for ZEND_EXT_STMT op1
+--FILE--
+
+--EXPECT--
+string(4) "1234"
diff --git a/Zend/tests/gh21603.phpt b/Zend/tests/gh21603.phpt
new file mode 100644
index 000000000000..ab2fbc44e797
--- /dev/null
+++ b/Zend/tests/gh21603.phpt
@@ -0,0 +1,22 @@
+--TEST--
+GH-21603: Missing addref for __unset
+--CREDITS--
+cnwangjihe
+--FILE--
+prop);
+
+?>
+--EXPECTF--
+object(C)#%d (0) {
+}
diff --git a/Zend/tests/gh21605.phpt b/Zend/tests/gh21605.phpt
new file mode 100644
index 000000000000..973339ad3bb9
--- /dev/null
+++ b/Zend/tests/gh21605.phpt
@@ -0,0 +1,24 @@
+--TEST--
+GH-21605: Missing addref for Countable::count()
+--CREDITS--
+cnwangjihe
+--FILE--
+
+--EXPECTF--
+object(C)#%d (0) {
+}
+int(42)
diff --git a/Zend/tests/gh_21699.phpt b/Zend/tests/gh_21699.phpt
new file mode 100644
index 000000000000..49b58365dabf
--- /dev/null
+++ b/Zend/tests/gh_21699.phpt
@@ -0,0 +1,31 @@
+--TEST--
+GH-21699: Assertion failure in shutdown_executor when error handler throws during self:: callable resolution
+--FILE--
+test();
+?>
+--EXPECTF--
+Fatal error: Uncaught Exception in %s:%d
+Stack trace:
+#0 %s(%d): {closure:%s}(%d, 'Use of "self" i%s', '%s', %d)
+#1 %s(%d): bar->test()
+#2 {main}
+
+Next TypeError: call_user_func(): Argument #1 ($callback) must be a valid callback, (null) in %s:%d
+Stack trace:
+#0 %s(%d): bar->test()
+#1 {main}
+ thrown in %s on line %d
diff --git a/Zend/tests/gh_21699_parent.phpt b/Zend/tests/gh_21699_parent.phpt
new file mode 100644
index 000000000000..73cae41f3f5b
--- /dev/null
+++ b/Zend/tests/gh_21699_parent.phpt
@@ -0,0 +1,32 @@
+--TEST--
+GH-21699 (parent::): no shutdown_executor trampoline assertion when error handler throws during parent:: callable resolution
+--FILE--
+test();
+?>
+--EXPECTF--
+Fatal error: Uncaught Exception in %s:%d
+Stack trace:
+#0 %s(%d): {closure:%s}(%d, 'Use of "parent"%s', '%s', %d)
+#1 %s(%d): Child->test()
+#2 {main}
+
+Next TypeError: call_user_func(): Argument #1 ($callback) must be a valid callback, (null) in %s:%d
+Stack trace:
+#0 %s(%d): Child->test()
+#1 {main}
+ thrown in %s on line %d
diff --git a/Zend/tests/gh_21699_static.phpt b/Zend/tests/gh_21699_static.phpt
new file mode 100644
index 000000000000..4d9604ebe77b
--- /dev/null
+++ b/Zend/tests/gh_21699_static.phpt
@@ -0,0 +1,31 @@
+--TEST--
+GH-21699 (static::): no shutdown_executor trampoline assertion when error handler throws during static:: callable resolution
+--FILE--
+test();
+?>
+--EXPECTF--
+Fatal error: Uncaught Exception in %s:%d
+Stack trace:
+#0 %s(%d): {closure:%s}(%d, 'Use of "static"%s', '%s', %d)
+#1 %s(%d): bar->test()
+#2 {main}
+
+Next TypeError: call_user_func(): Argument #1 ($callback) must be a valid callback, (null) in %s:%d
+Stack trace:
+#0 %s(%d): bar->test()
+#1 {main}
+ thrown in %s on line %d
diff --git a/Zend/tests/lazy_objects/gh18038-002.phpt b/Zend/tests/lazy_objects/gh18038-002.phpt
index 4c12f21de811..d363731c62a0 100644
--- a/Zend/tests/lazy_objects/gh18038-002.phpt
+++ b/Zend/tests/lazy_objects/gh18038-002.phpt
@@ -34,5 +34,4 @@ var_dump($obj->prop);
--EXPECT--
init
string(19) "RealInstance::__set"
-string(12) "Proxy::__set"
int(2)
diff --git a/Zend/tests/lazy_objects/gh18038-004.phpt b/Zend/tests/lazy_objects/gh18038-004.phpt
index 8810efb6bec2..c1495c5a6d8d 100644
--- a/Zend/tests/lazy_objects/gh18038-004.phpt
+++ b/Zend/tests/lazy_objects/gh18038-004.phpt
@@ -36,7 +36,6 @@ var_dump($real->prop);
--EXPECTF--
init
string(19) "RealInstance::__get"
-string(12) "Proxy::__get"
Warning: Undefined property: RealInstance::$prop in %s on line %d
NULL
diff --git a/Zend/tests/lazy_objects/gh18038-007.phpt b/Zend/tests/lazy_objects/gh18038-007.phpt
index 9925190a1980..4c7c0d0b4b0a 100644
--- a/Zend/tests/lazy_objects/gh18038-007.phpt
+++ b/Zend/tests/lazy_objects/gh18038-007.phpt
@@ -36,6 +36,5 @@ var_dump(isset($real->prop['']));
--EXPECT--
init
string(21) "RealInstance::__isset"
-string(14) "Proxy::__isset"
bool(false)
bool(false)
diff --git a/Zend/tests/lazy_objects/gh18038-009.phpt b/Zend/tests/lazy_objects/gh18038-009.phpt
index 3c165a71ccff..11067cdb970b 100644
--- a/Zend/tests/lazy_objects/gh18038-009.phpt
+++ b/Zend/tests/lazy_objects/gh18038-009.phpt
@@ -36,6 +36,5 @@ var_dump(isset($real->prop));
--EXPECT--
init
string(21) "RealInstance::__isset"
-string(14) "Proxy::__isset"
bool(false)
bool(false)
diff --git a/Zend/tests/lazy_objects/gh20875.phpt b/Zend/tests/lazy_objects/gh20875.phpt
index 72e16011320c..ff036edabd59 100644
--- a/Zend/tests/lazy_objects/gh20875.phpt
+++ b/Zend/tests/lazy_objects/gh20875.phpt
@@ -31,14 +31,6 @@ Warning: Undefined variable $a in %s on line %d
Warning: Undefined variable $v in %s on line %d
-Notice: Indirect modification of overloaded property A::$b has no effect in %s on line %d
-
-Warning: Undefined variable $x in %s on line %d
-
-Notice: Object of class stdClass could not be converted to int in %s on line %d
-
-Warning: Undefined variable $v in %s on line %d
-
Notice: Indirect modification of overloaded property A::$f has no effect in %s on line %d
Fatal error: Uncaught Error: Cannot assign by reference to overloaded object in %s:%d
diff --git a/Zend/tests/lazy_objects/gh21478-isset.phpt b/Zend/tests/lazy_objects/gh21478-isset.phpt
new file mode 100644
index 000000000000..9138984af01b
--- /dev/null
+++ b/Zend/tests/lazy_objects/gh21478-isset.phpt
@@ -0,0 +1,30 @@
+--TEST--
+GH-21478: __isset on lazy proxy should not double-invoke when real instance guard is set
+--FILE--
+{$name});
+ }
+}
+
+class Bar extends Foo {}
+
+$rc = new ReflectionClass(Bar::class);
+$proxy = $rc->newLazyProxy(function () {
+ echo "Init\n";
+ return new Foo();
+});
+
+$real = $rc->initializeLazyObject($proxy);
+isset($real->x);
+
+?>
+--EXPECT--
+Init
+__isset($x) on Foo
diff --git a/Zend/tests/lazy_objects/gh21478-proxy-get-override.phpt b/Zend/tests/lazy_objects/gh21478-proxy-get-override.phpt
new file mode 100644
index 000000000000..520c8f662353
--- /dev/null
+++ b/Zend/tests/lazy_objects/gh21478-proxy-get-override.phpt
@@ -0,0 +1,30 @@
+--TEST--
+GH-21478: Proxy's own __get runs when accessed directly (not from real instance)
+--FILE--
+newLazyProxy(function () {
+ return new Foo();
+});
+$rc->initializeLazyObject($proxy);
+
+$proxy->x;
+
+?>
+--EXPECT--
+Bar x
diff --git a/Zend/tests/lazy_objects/gh21478-proxy-get-ref-forward.phpt b/Zend/tests/lazy_objects/gh21478-proxy-get-ref-forward.phpt
new file mode 100644
index 000000000000..fa737cf18f2e
--- /dev/null
+++ b/Zend/tests/lazy_objects/gh21478-proxy-get-ref-forward.phpt
@@ -0,0 +1,32 @@
+--TEST--
+GH-21478: No assertion failure when &__get forwards through initialized lazy proxy
+--FILE--
+{$name};
+ }
+}
+
+class Bar extends Foo {}
+
+$rc = new ReflectionClass(Bar::class);
+$proxy = $rc->newLazyProxy(function () {
+ echo "Init\n";
+ return new Foo();
+});
+
+$real = $rc->initializeLazyObject($proxy);
+$a = &$real->x;
+var_dump($a);
+?>
+--EXPECTF--
+Init
+Foo::__get($x) on Foo
+
+Warning: Undefined property: Foo::$x in %s on line %d
+NULL
diff --git a/Zend/tests/lazy_objects/gh21478-set.phpt b/Zend/tests/lazy_objects/gh21478-set.phpt
new file mode 100644
index 000000000000..0b2f872de11a
--- /dev/null
+++ b/Zend/tests/lazy_objects/gh21478-set.phpt
@@ -0,0 +1,32 @@
+--TEST--
+GH-21478: __set on lazy proxy should not double-invoke when real instance guard is set
+--FILE--
+{$name} = $value;
+ }
+}
+
+#[AllowDynamicProperties]
+class Bar extends Foo {}
+
+$rc = new ReflectionClass(Bar::class);
+$proxy = $rc->newLazyProxy(function () {
+ echo "Init\n";
+ return new Foo();
+});
+
+$real = $rc->initializeLazyObject($proxy);
+$real->x = 1;
+
+?>
+--EXPECT--
+Init
+__set($x) on Foo
diff --git a/Zend/tests/lazy_objects/gh21478-unset.phpt b/Zend/tests/lazy_objects/gh21478-unset.phpt
new file mode 100644
index 000000000000..5febbd235d82
--- /dev/null
+++ b/Zend/tests/lazy_objects/gh21478-unset.phpt
@@ -0,0 +1,30 @@
+--TEST--
+GH-21478: __unset on lazy proxy should not double-invoke when real instance guard is set
+--FILE--
+{$name});
+ }
+}
+
+class Bar extends Foo {}
+
+$rc = new ReflectionClass(Bar::class);
+$proxy = $rc->newLazyProxy(function () {
+ echo "Init\n";
+ return new Foo();
+});
+
+$real = $rc->initializeLazyObject($proxy);
+unset($real->x);
+
+?>
+--EXPECT--
+Init
+__unset($x) on Foo
diff --git a/Zend/tests/lazy_objects/gh21478.phpt b/Zend/tests/lazy_objects/gh21478.phpt
new file mode 100644
index 000000000000..aaa226a9a09a
--- /dev/null
+++ b/Zend/tests/lazy_objects/gh21478.phpt
@@ -0,0 +1,32 @@
+--TEST--
+GH-21478 (Property access on lazy proxy may invoke magic method despite real instance guards)
+--FILE--
+{$name};
+ }
+}
+
+class Bar extends Foo {}
+
+$rc = new ReflectionClass(Bar::class);
+$proxy = $rc->newLazyProxy(function () {
+ echo "Init\n";
+ return new Foo();
+});
+
+$real = $rc->initializeLazyObject($proxy);
+$real->x;
+
+?>
+--EXPECTF--
+Init
+__get($x) on Foo
+
+Warning: Undefined property: Foo::$x in %s on line %d
diff --git a/Zend/tests/partial_application/assert.phpt b/Zend/tests/partial_application/assert.phpt
new file mode 100644
index 000000000000..fe36e687f8d5
--- /dev/null
+++ b/Zend/tests/partial_application/assert.phpt
@@ -0,0 +1,35 @@
+--TEST--
+PFA of assert() behaves like a dynamic call to assert()
+--FILE--
+getMessage(), "\n";
+}
+
+try {
+ echo "# Dynamic call:\n";
+ (function ($f) { $f(false); })('assert');
+} catch (Error $e) {
+ echo $e::class, ": ", $e->getMessage() ?: '(no message)', "\n";
+}
+
+try {
+ echo "# PFA call:\n";
+ $f = assert(?);
+ $f(false);
+} catch (Error $e) {
+ echo $e::class, ": ", $e->getMessage() ?: '(no message)', "\n";
+}
+
+?>
+--EXPECT--
+# Static call:
+AssertionError: assert(false)
+# Dynamic call:
+AssertionError: (no message)
+# PFA call:
+AssertionError: (no message)
diff --git a/Zend/tests/partial_application/attributes_001.phpt b/Zend/tests/partial_application/attributes_001.phpt
new file mode 100644
index 000000000000..827ad41321ec
--- /dev/null
+++ b/Zend/tests/partial_application/attributes_001.phpt
@@ -0,0 +1,88 @@
+--TEST--
+PFA inherits NoDiscard and SensitiveParameter attributes
+--FILE--
+getAttributes());
+
+ foreach ($r->getParameters() as $i => $p) {
+ echo "Parameter $i:\n";
+ var_dump($p->getAttributes());
+ }
+}
+
+echo "# Orig attributes:\n";
+
+dump_attributes('f');
+
+$f = f(1, ?, ?, ...);
+
+echo "# PFA attributes:\n";
+
+dump_attributes($f);
+
+?>
+--EXPECTF--
+# Orig attributes:
+array(2) {
+ [0]=>
+ object(ReflectionAttribute)#%d (1) {
+ ["name"]=>
+ string(9) "NoDiscard"
+ }
+ [1]=>
+ object(ReflectionAttribute)#%d (1) {
+ ["name"]=>
+ string(4) "Test"
+ }
+}
+Parameter 0:
+array(0) {
+}
+Parameter 1:
+array(1) {
+ [0]=>
+ object(ReflectionAttribute)#%d (1) {
+ ["name"]=>
+ string(18) "SensitiveParameter"
+ }
+}
+Parameter 2:
+array(1) {
+ [0]=>
+ object(ReflectionAttribute)#%d (1) {
+ ["name"]=>
+ string(4) "Test"
+ }
+}
+# PFA attributes:
+array(1) {
+ [0]=>
+ object(ReflectionAttribute)#%d (1) {
+ ["name"]=>
+ string(9) "NoDiscard"
+ }
+}
+Parameter 0:
+array(1) {
+ [0]=>
+ object(ReflectionAttribute)#%d (1) {
+ ["name"]=>
+ string(18) "SensitiveParameter"
+ }
+}
+Parameter 1:
+array(0) {
+}
+Parameter 2:
+array(0) {
+}
diff --git a/Zend/tests/partial_application/attributes_002.phpt b/Zend/tests/partial_application/attributes_002.phpt
new file mode 100644
index 000000000000..be1f1612f938
--- /dev/null
+++ b/Zend/tests/partial_application/attributes_002.phpt
@@ -0,0 +1,19 @@
+--TEST--
+PFA preserves #[SensitiveParameter]
+--FILE--
+
+--EXPECTF--
+Fatal error: Uncaught Exception in %s:%d
+Stack trace:
+#0 %s(%d): f(1, Object(SensitiveParameterValue), 3, Object(SensitiveParameterValue), Object(SensitiveParameterValue))
+#1 %s(%d): {closure:pfa:%s:7}(Object(SensitiveParameterValue), 3, Object(SensitiveParameterValue), Object(SensitiveParameterValue))
+#2 {main}
+ thrown in %s on line %d
diff --git a/Zend/tests/partial_application/attributes_003.phpt b/Zend/tests/partial_application/attributes_003.phpt
new file mode 100644
index 000000000000..d113d02eb8f7
--- /dev/null
+++ b/Zend/tests/partial_application/attributes_003.phpt
@@ -0,0 +1,16 @@
+--TEST--
+PFA preserves #[NoDiscard]
+--FILE--
+
+--EXPECTF--
+Warning: The return value of function {closure:%s}() should either be used or intentionally ignored by casting it as (void) in %s on line 7
diff --git a/Zend/tests/partial_application/clone.phpt b/Zend/tests/partial_application/clone.phpt
new file mode 100644
index 000000000000..f778d776b717
--- /dev/null
+++ b/Zend/tests/partial_application/clone.phpt
@@ -0,0 +1,50 @@
+--TEST--
+clone() can be partially applied
+--FILE--
+ 7]));
+
+$clone = clone(?, ['a' => 8]);
+var_dump($clone(new C(9, 10)));
+
+?>
+--EXPECTF--
+object(C)#%d (2) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+}
+object(C)#%d (2) {
+ ["a"]=>
+ int(3)
+ ["b"]=>
+ int(4)
+}
+object(C)#%d (2) {
+ ["a"]=>
+ int(7)
+ ["b"]=>
+ int(6)
+}
+object(C)#%d (2) {
+ ["a"]=>
+ int(8)
+ ["b"]=>
+ int(10)
+}
diff --git a/Zend/tests/partial_application/compile_errors_001.phpt b/Zend/tests/partial_application/compile_errors_001.phpt
new file mode 100644
index 000000000000..f08495a1f1e5
--- /dev/null
+++ b/Zend/tests/partial_application/compile_errors_001.phpt
@@ -0,0 +1,8 @@
+--TEST--
+PFA compile errors: multiple variadic placeholders
+--FILE--
+
+--EXPECTF--
+Fatal error: Variadic placeholder may only appear once in %s on line %d
diff --git a/Zend/tests/partial_application/compile_errors_002.phpt b/Zend/tests/partial_application/compile_errors_002.phpt
new file mode 100644
index 000000000000..b6a2073a8363
--- /dev/null
+++ b/Zend/tests/partial_application/compile_errors_002.phpt
@@ -0,0 +1,8 @@
+--TEST--
+PFA compile errors: variadic placeholder must be last
+--FILE--
+
+--EXPECTF--
+Fatal error: Variadic placeholder must be last in %s on line %d
diff --git a/Zend/tests/partial_application/compile_errors_003.phpt b/Zend/tests/partial_application/compile_errors_003.phpt
new file mode 100644
index 000000000000..26ff8435111b
--- /dev/null
+++ b/Zend/tests/partial_application/compile_errors_003.phpt
@@ -0,0 +1,8 @@
+--TEST--
+PFA compile errors: placeholders can not appear after named args
+--FILE--
+
+--EXPECTF--
+Fatal error: Cannot use positional argument after named argument in %s on line %d
diff --git a/Zend/tests/partial_application/compile_errors_004.phpt b/Zend/tests/partial_application/compile_errors_004.phpt
new file mode 100644
index 000000000000..ac7ec163c5da
--- /dev/null
+++ b/Zend/tests/partial_application/compile_errors_004.phpt
@@ -0,0 +1,8 @@
+--TEST--
+PFA compile errors: variadic placeholder must be last, including after named args
+--FILE--
+
+--EXPECTF--
+Fatal error: Variadic placeholder must be last in %s on line %d
diff --git a/Zend/tests/partial_application/compile_errors_005.phpt b/Zend/tests/partial_application/compile_errors_005.phpt
new file mode 100644
index 000000000000..30e4aa12b488
--- /dev/null
+++ b/Zend/tests/partial_application/compile_errors_005.phpt
@@ -0,0 +1,8 @@
+--TEST--
+PFA compile errors: variadic placeholder must be last, including after positional args
+--FILE--
+
+--EXPECTF--
+Fatal error: Variadic placeholder must be last in %s on line %d
diff --git a/Zend/tests/partial_application/compile_errors_006.phpt b/Zend/tests/partial_application/compile_errors_006.phpt
new file mode 100644
index 000000000000..8549c671e906
--- /dev/null
+++ b/Zend/tests/partial_application/compile_errors_006.phpt
@@ -0,0 +1,8 @@
+--TEST--
+PFA compile errors: can not use unpacking in PFA, including with variadic placeholders
+--FILE--
+ "bar"], ...);
+?>
+--EXPECTF--
+Fatal error: Cannot combine partial application and unpacking in %s on line %d
diff --git a/Zend/tests/partial_application/deprecated.phpt b/Zend/tests/partial_application/deprecated.phpt
new file mode 100644
index 000000000000..5a6280347cfc
--- /dev/null
+++ b/Zend/tests/partial_application/deprecated.phpt
@@ -0,0 +1,14 @@
+--TEST--
+PFAs may emit deprecation warnings
+--FILE--
+
+--EXPECTF--
+Deprecated: Function f() is deprecated in %s on line %d
diff --git a/Zend/tests/partial_application/errors_001.phpt b/Zend/tests/partial_application/errors_001.phpt
new file mode 100644
index 000000000000..2d5348cb28af
--- /dev/null
+++ b/Zend/tests/partial_application/errors_001.phpt
@@ -0,0 +1,62 @@
+--TEST--
+PFA errors: PFA instantiation follows the usual argument count validation
+--FILE--
+getMessage());
+}
+
+try {
+ foo(?, ?, ?, ?);
+} catch (Error $ex) {
+ printf("%s: %s\n", $ex::class, $ex->getMessage());
+}
+
+try {
+ $c = new C();
+ $c->f(?);
+} catch (Error $ex) {
+ printf("%s: %s\n", $ex::class, $ex->getMessage());
+}
+
+try {
+ property_exists(?);
+} catch (Error $ex) {
+ printf("%s: %s\n", $ex::class, $ex->getMessage());
+}
+
+try {
+ usleep(?, ?);
+} catch (Error $ex) {
+ printf("%s: %s\n", $ex::class, $ex->getMessage());
+}
+
+try {
+ foo(?, ?, ?, ?, ...);
+} catch (Error $ex) {
+ printf("%s: %s\n", $ex::class, $ex->getMessage());
+}
+
+/* It is allowed to specify less than the number of required params, when there
+ * is a variadic placeholder */
+foo(?, ...);
+
+?>
+--EXPECT--
+ArgumentCountError: Partial application of foo() expects exactly 3 arguments, 1 given
+ArgumentCountError: Partial application of foo() expects at most 3 arguments, 4 given
+ArgumentCountError: Partial application of C::f() expects exactly 3 arguments, 1 given
+ArgumentCountError: Partial application of property_exists() expects exactly 2 arguments, 1 given
+ArgumentCountError: Partial application of usleep() expects at most 1 arguments, 2 given
+ArgumentCountError: Partial application of foo() expects at most 3 arguments, 4 given
diff --git a/Zend/tests/partial_application/errors_002.phpt b/Zend/tests/partial_application/errors_002.phpt
new file mode 100644
index 000000000000..0132d8873e2a
--- /dev/null
+++ b/Zend/tests/partial_application/errors_002.phpt
@@ -0,0 +1,15 @@
+--TEST--
+PFA errors: named parameter that resolve to the position of a placeholder is an error
+--FILE--
+getMessage());
+}
+?>
+--EXPECT--
+Error: Named parameter $a overwrites previous placeholder
diff --git a/Zend/tests/partial_application/errors_003.phpt b/Zend/tests/partial_application/errors_003.phpt
new file mode 100644
index 000000000000..85ecf398fa1b
--- /dev/null
+++ b/Zend/tests/partial_application/errors_003.phpt
@@ -0,0 +1,74 @@
+--TEST--
+PFA errors: PFA call follows the usual argument count validation
+--FILE--
+getMessage());
+}
+
+$foo = foo(?, ?);
+
+try {
+ $foo(1);
+} catch (Error $ex) {
+ printf("%s: %s\n", $ex::class, $ex->getMessage());
+}
+
+$bar = bar(?, ?, ...);
+
+try {
+ $bar(1);
+} catch (Error $ex) {
+ printf("%s: %s\n", $ex::class, $ex->getMessage());
+}
+
+class Foo {
+ public function bar($a, ...$b) {}
+}
+
+$foo = new Foo;
+
+$bar = $foo->bar(?);
+
+try {
+ $bar();
+} catch (Error $ex) {
+ printf("%s: %s\n", $ex::class, $ex->getMessage());
+}
+
+$repeat = str_repeat('a', ...);
+
+try {
+ $repeat();
+} catch (Error $ex) {
+ printf("%s: %s\n", $ex::class, $ex->getMessage());
+}
+
+$usleep = usleep(?);
+
+try {
+ $usleep();
+} catch (Error $ex) {
+ printf("%s: %s\n", $ex::class, $ex->getMessage());
+}
+
+$usleep(1, 2);
+
+?>
+--EXPECTF--
+ArgumentCountError: Too few arguments to function {closure:%s:%d}(), 0 passed in %s on line %d and exactly 1 expected
+ArgumentCountError: Too few arguments to function {closure:%s:%d}(), 1 passed in %s on line %d and exactly 2 expected
+ArgumentCountError: Too few arguments to function {closure:%s:%d}(), 1 passed in %s on line %d and exactly 3 expected
+ArgumentCountError: Too few arguments to function Foo::{closure:%s:%d}(), 0 passed in %s on line %d and exactly 1 expected
+ArgumentCountError: Too few arguments to function {closure:%s:%d}(), 0 passed in %s on line %d and exactly 1 expected
+ArgumentCountError: Too few arguments to function {closure:%s:%d}(), 0 passed in %s on line %d and exactly 1 expected
diff --git a/Zend/tests/partial_application/errors_004.phpt b/Zend/tests/partial_application/errors_004.phpt
new file mode 100644
index 000000000000..e5e1432753b2
--- /dev/null
+++ b/Zend/tests/partial_application/errors_004.phpt
@@ -0,0 +1,16 @@
+--TEST--
+PFA errors: not specifying a required param is an error
+--FILE--
+
+--EXPECTF--
+Fatal error: Uncaught ArgumentCountError: f(): Argument #2 ($b) not passed in %s:6
+Stack trace:
+#0 {main}
+ thrown in %s on line %d
diff --git a/Zend/tests/partial_application/errors_005.phpt b/Zend/tests/partial_application/errors_005.phpt
new file mode 100644
index 000000000000..2c28f0565e2d
--- /dev/null
+++ b/Zend/tests/partial_application/errors_005.phpt
@@ -0,0 +1,15 @@
+--TEST--
+PFA errors: Can not fetch default parameter value for Closure::__invoke()
+--FILE--
+__invoke(0, 0, ?);
+} catch (Error $e) {
+ echo $e::class, ": ", $e->getMessage(), "\n";
+}
+
+?>
+--EXPECT--
+ArgumentCountError: Closure::__invoke(): Argument #3 ($c) must be passed explicitly, because the default value is not known
diff --git a/Zend/tests/partial_application/errors_006.phpt b/Zend/tests/partial_application/errors_006.phpt
new file mode 100644
index 000000000000..9534bb40ee54
--- /dev/null
+++ b/Zend/tests/partial_application/errors_006.phpt
@@ -0,0 +1,45 @@
+--TEST--
+PFA errors: Some internal function parameters have UNKNOWN default value
+--FILE--
+ array_keys($array, ???, true)
+ $f = array_keys(?, strict: true);
+} catch (Error $e) {
+ echo $e::class, ": ", $e->getMessage(), "\n";
+}
+
+try {
+ // fn (array $array, mixed $filter_value = ???) => array_keys($array, $filter_value, true)
+ $f = array_keys(?, strict: true, ...);
+} catch (Error $e) {
+ echo $e::class, ": ", $e->getMessage(), "\n";
+}
+
+?>
+--EXPECT--
+array(1) {
+ [0]=>
+ int(1)
+}
+array(0) {
+}
+array(1) {
+ [0]=>
+ int(1)
+}
+array(0) {
+}
+ArgumentCountError: array_keys(): Argument #2 ($filter_value) must be passed explicitly, because the default value is not known
+ArgumentCountError: array_keys(): Argument #2 ($filter_value) must be passed explicitly, because the default value is not known
diff --git a/Zend/tests/partial_application/export_001.phpt b/Zend/tests/partial_application/export_001.phpt
new file mode 100644
index 000000000000..b48146bcc65a
--- /dev/null
+++ b/Zend/tests/partial_application/export_001.phpt
@@ -0,0 +1,14 @@
+--TEST--
+PFA AST export
+--INI--
+assert.exception=1
+--FILE--
+getMessage());
+}
+?>
+--EXPECT--
+AssertionError: assert(0 && foo(?) && foo(new stdClass(), bar: 1, ...))
diff --git a/Zend/tests/partial_application/extra_named.phpt b/Zend/tests/partial_application/extra_named.phpt
new file mode 100644
index 000000000000..4dd80cfa0127
--- /dev/null
+++ b/Zend/tests/partial_application/extra_named.phpt
@@ -0,0 +1,49 @@
+--TEST--
+PFA extra named parameters are forwarded to the actual function
+--FILE--
+
+--EXPECT--
+array(3) {
+ ["foo"]=>
+ string(3) "foo"
+ ["bar"]=>
+ string(3) "bar"
+ ["baz"]=>
+ string(3) "baz"
+}
+array(2) {
+ ["bar"]=>
+ string(3) "bar"
+ ["baz"]=>
+ string(3) "baz"
+}
+array(2) {
+ ["foo"]=>
+ string(3) "foo"
+ ["bar"]=>
+ string(3) "bar"
+}
diff --git a/Zend/tests/partial_application/function_name.phpt b/Zend/tests/partial_application/function_name.phpt
new file mode 100644
index 000000000000..68d2ccf84871
--- /dev/null
+++ b/Zend/tests/partial_application/function_name.phpt
@@ -0,0 +1,40 @@
+--TEST--
+Partial application function name
+--FILE--
+getName());
+ }
+}
+
+function f() {
+ echo "# From a function:\n";
+ var_dump((new ReflectionFunction(g(?)))->getName());
+
+ echo "# Declared on same line:\n";
+ [$a, $b] = [g(?), g(?)];
+ var_dump((new ReflectionFunction($a))->getName(), (new ReflectionFunction($b))->getName());
+}
+
+f();
+C::m();
+
+echo "# From global scope:\n";
+var_dump((new ReflectionFunction(g(?)))->getName());
+
+?>
+--EXPECTF--
+# From a function:
+string(20) "{closure:pfa:f():14}"
+# Declared on same line:
+string(20) "{closure:pfa:f():17}"
+string(20) "{closure:pfa:f():17}"
+# From a method:
+string(22) "{closure:pfa:C::m():8}"
+# From global scope:
+string(%d) "{closure:pfa:%sfunction_name.php:25}"
diff --git a/Zend/tests/partial_application/fuzz_001.phpt b/Zend/tests/partial_application/fuzz_001.phpt
new file mode 100644
index 000000000000..790162ba6a36
--- /dev/null
+++ b/Zend/tests/partial_application/fuzz_001.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Closure application fuzz 001
+--FILE--
+
+--EXPECTF--
+Closure [ function {closure:%s:%d} ] {
+ @@ %s 4 - 4
+
+ - Bound Variables [2] {
+ Variable #0 [ $fn ]
+ Variable #1 [ $a ]
+ }
+
+ - Parameters [1] {
+ Parameter #0 [ $b ]
+ }
+}
diff --git a/Zend/tests/partial_application/fuzz_002.phpt b/Zend/tests/partial_application/fuzz_002.phpt
new file mode 100644
index 000000000000..685cb706e69b
--- /dev/null
+++ b/Zend/tests/partial_application/fuzz_002.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Closure application fuzz 002
+--FILE--
+
+--EXPECTF--
+OK
diff --git a/Zend/tests/partial_application/fuzz_003.phpt b/Zend/tests/partial_application/fuzz_003.phpt
new file mode 100644
index 000000000000..6e9d583fda99
--- /dev/null
+++ b/Zend/tests/partial_application/fuzz_003.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Closure application fuzz 003
+--FILE--
+method(1, ...);
+$bar(2);
+?>
+--EXPECT--
+array(2) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+}
diff --git a/Zend/tests/partial_application/fuzz_004.phpt b/Zend/tests/partial_application/fuzz_004.phpt
new file mode 100644
index 000000000000..ea005304a3af
--- /dev/null
+++ b/Zend/tests/partial_application/fuzz_004.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Closure application fuzz 004
+--FILE--
+__invoke(UNDEFINED);
+} catch (\Throwable $e) {
+ echo $e::class, ": ", $e->getMessage(), "\n";
+}
+
+?>
+--EXPECT--
+Error: Undefined constant "UNDEFINED"
diff --git a/Zend/tests/partial_application/fuzz_005.phpt b/Zend/tests/partial_application/fuzz_005.phpt
new file mode 100644
index 000000000000..ea04862d8399
--- /dev/null
+++ b/Zend/tests/partial_application/fuzz_005.phpt
@@ -0,0 +1,16 @@
+--TEST--
+PFA fuzz 005
+--FILE--
+
+==DONE==
+--EXPECT--
+==DONE==
diff --git a/Zend/tests/partial_application/fuzz_006.phpt b/Zend/tests/partial_application/fuzz_006.phpt
new file mode 100644
index 000000000000..26ec6e3e4dd1
--- /dev/null
+++ b/Zend/tests/partial_application/fuzz_006.phpt
@@ -0,0 +1,16 @@
+--TEST--
+PFA fuzz 006
+--FILE--
+
+--EXPECT--
+int(1)
diff --git a/Zend/tests/partial_application/fuzz_007.phpt b/Zend/tests/partial_application/fuzz_007.phpt
new file mode 100644
index 000000000000..123ce29d8b18
--- /dev/null
+++ b/Zend/tests/partial_application/fuzz_007.phpt
@@ -0,0 +1,19 @@
+--TEST--
+PFA fuzz 007
+--FILE--
+getMessage(), "\n";
+}
+
+?>
+--EXPECT--
+Undefined constant "UNDEFINED"
diff --git a/Zend/tests/partial_application/hook.phpt b/Zend/tests/partial_application/hook.phpt
new file mode 100644
index 000000000000..6402c5d01e74
--- /dev/null
+++ b/Zend/tests/partial_application/hook.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Parent property hook call can not be partially applied
+--FILE--
+a = 1;
+
+?>
+--EXPECTF--
+Fatal error: Cannot create Closure for parent property hook call in %s on line %d
diff --git a/Zend/tests/partial_application/instance_polymorphism.phpt b/Zend/tests/partial_application/instance_polymorphism.phpt
new file mode 100644
index 000000000000..59fb5795d60f
--- /dev/null
+++ b/Zend/tests/partial_application/instance_polymorphism.phpt
@@ -0,0 +1,43 @@
+--TEST--
+PFA: instance polymorphism
+--FILE--
+m(?);
+ }
+}
+
+class C extends P {
+ public function m(string|array $b): void {
+ echo __METHOD__, PHP_EOL;
+ var_dump($b);
+ }
+}
+
+for ($i = 0; $i < 2; $i++) {
+ (new P())->get()(a: 'a');
+ (new C())->get()(b: []);
+}
+
+?>
+--EXPECT--
+P::m
+string(1) "a"
+C::m
+array(0) {
+}
+P::m
+string(1) "a"
+C::m
+array(0) {
+}
diff --git a/Zend/tests/partial_application/invokable.phpt b/Zend/tests/partial_application/invokable.phpt
new file mode 100644
index 000000000000..c21030e7733a
--- /dev/null
+++ b/Zend/tests/partial_application/invokable.phpt
@@ -0,0 +1,51 @@
+--TEST--
+__invoke() can be partially applied
+--FILE--
+
+--EXPECTF--
+Closure [ public method {closure:%s:%d} ] {
+ @@ %s.php 11 - 11
+
+ - Parameters [2] {
+ Parameter #0 [ int $a ]
+ Parameter #1 [ object $b ]
+ }
+ - Return [ C ]
+}
+
+Closure [ public method {closure:%s:%d} ] {
+ @@ %s.php 15 - 15
+
+ - Bound Variables [1] {
+ Variable #0 [ $b ]
+ }
+
+ - Parameters [1] {
+ Parameter #0 [ int $a ]
+ }
+ - Return [ C ]
+}
+
+int(1)
+object(stdClass)#%d (0) {
+}
diff --git a/Zend/tests/partial_application/jit_001.phpt b/Zend/tests/partial_application/jit_001.phpt
new file mode 100644
index 000000000000..84aefa05ab28
--- /dev/null
+++ b/Zend/tests/partial_application/jit_001.phpt
@@ -0,0 +1,9 @@
+--TEST--
+PFA JIT 001
+--FILE--
+
+--EXPECT--
+int(1)
+int(2)
diff --git a/Zend/tests/partial_application/magic_001.phpt b/Zend/tests/partial_application/magic_001.phpt
new file mode 100644
index 000000000000..6cd6044c62de
--- /dev/null
+++ b/Zend/tests/partial_application/magic_001.phpt
@@ -0,0 +1,81 @@
+--TEST--
+__call() can be partially applied
+--FILE--
+method(?);
+
+echo (string) new ReflectionFunction($bar);
+
+try {
+ $bar();
+} catch (Error $ex) {
+ printf("%s: %s\n", $ex::class, $ex->getMessage());
+}
+
+$bar(1, 2);
+$bar(1);
+
+$bar = $foo->method(?, ...);
+
+echo (string) new ReflectionFunction($bar);
+
+$bar(10);
+$bar(10, 20);
+
+$bar = $foo->method(new Foo, ...);
+
+echo (string) new ReflectionFunction($bar);
+
+$bar(100);
+?>
+--EXPECTF--
+Closure [ public method {closure:%s:%d} ] {
+ @@ %s 12 - 12
+
+ - Parameters [1] {
+ Parameter #0 [ mixed $arguments0 ]
+ }
+}
+ArgumentCountError: Too few arguments to function Foo::{closure:%s:%d}(), 0 passed in %s on line %d and exactly 1 expected
+Foo::method
+int(1)
+Foo::method
+int(1)
+Closure [ public method {closure:%s:%d} ] {
+ @@ %s 25 - 25
+
+ - Parameters [2] {
+ Parameter #0 [ mixed $arguments0 ]
+ Parameter #1 [ mixed ...$arguments ]
+ }
+}
+Foo::method
+int(10)
+Foo::method
+int(10)
+int(20)
+Closure [ public method {closure:%s:%d} ] {
+ @@ %s 32 - 32
+
+ - Bound Variables [1] {
+ Variable #0 [ $arguments0 ]
+ }
+
+ - Parameters [1] {
+ Parameter #0 [ mixed ...$arguments ]
+ }
+}
+Foo::method
+object(Foo)#%d (0) {
+}
+int(100)
diff --git a/Zend/tests/partial_application/magic_002.phpt b/Zend/tests/partial_application/magic_002.phpt
new file mode 100644
index 000000000000..d91ef7a7afe2
--- /dev/null
+++ b/Zend/tests/partial_application/magic_002.phpt
@@ -0,0 +1,72 @@
+--TEST--
+__callStatic() can be partially applied
+--FILE--
+
+--EXPECTF--
+Closure [ static public method {closure:%s:%d} ] {
+ @@ %s 10 - 10
+
+ - Parameters [1] {
+ Parameter #0 [ mixed $arguments0 ]
+ }
+}
+Foo::method
+int(1)
+Foo::method
+int(1)
+Closure [ static public method {closure:%s:%d} ] {
+ @@ %s 17 - 17
+
+ - Parameters [2] {
+ Parameter #0 [ mixed $arguments0 ]
+ Parameter #1 [ mixed ...$arguments ]
+ }
+}
+Foo::method
+int(10)
+Foo::method
+int(10)
+int(20)
+Closure [ static public method {closure:%s:%d} ] {
+ @@ %s 24 - 24
+
+ - Bound Variables [1] {
+ Variable #0 [ $arguments0 ]
+ }
+
+ - Parameters [1] {
+ Parameter #0 [ mixed ...$arguments ]
+ }
+}
+Foo::method
+object(Foo)#%d (0) {
+}
+int(100)
diff --git a/Zend/tests/partial_application/magic_003.phpt b/Zend/tests/partial_application/magic_003.phpt
new file mode 100644
index 000000000000..242403ea38fc
--- /dev/null
+++ b/Zend/tests/partial_application/magic_003.phpt
@@ -0,0 +1,13 @@
+--TEST--
+PFA magic trampoline release (result unused)
+--FILE--
+
+--EXPECT--
+OK
diff --git a/Zend/tests/partial_application/magic_004.phpt b/Zend/tests/partial_application/magic_004.phpt
new file mode 100644
index 000000000000..8ef93a91ce83
--- /dev/null
+++ b/Zend/tests/partial_application/magic_004.phpt
@@ -0,0 +1,14 @@
+--TEST--
+PFA magic trampoline release (result used)
+--FILE--
+
+--EXPECT--
+OK
diff --git a/Zend/tests/partial_application/magic_005.phpt b/Zend/tests/partial_application/magic_005.phpt
new file mode 100644
index 000000000000..e70ed90b1767
--- /dev/null
+++ b/Zend/tests/partial_application/magic_005.phpt
@@ -0,0 +1,29 @@
+--TEST--
+PFA magic null ptr deref in arginfo
+--FILE--
+method(?);
+var_dump($bar);
+?>
+--EXPECTF--
+object(Closure)#%d (%d) {
+ ["name"]=>
+ string(%d) "{closure:%s}"
+ ["file"]=>
+ string(%d) "%smagic_005.php"
+ ["line"]=>
+ int(7)
+ ["this"]=>
+ object(Foo)#%d (0) {
+ }
+ ["parameter"]=>
+ array(1) {
+ ["$arguments0"]=>
+ string(10) ""
+ }
+}
diff --git a/Zend/tests/partial_application/magic_006.phpt b/Zend/tests/partial_application/magic_006.phpt
new file mode 100644
index 000000000000..29564d8b615a
--- /dev/null
+++ b/Zend/tests/partial_application/magic_006.phpt
@@ -0,0 +1,20 @@
+--TEST--
+PFA magic varargs
+--FILE--
+method(1,...);
+$bar(2);
+?>
+--EXPECT--
+array(2) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+}
diff --git a/Zend/tests/partial_application/named_placeholders.phpt b/Zend/tests/partial_application/named_placeholders.phpt
new file mode 100644
index 000000000000..7d4a11f93624
--- /dev/null
+++ b/Zend/tests/partial_application/named_placeholders.phpt
@@ -0,0 +1,117 @@
+--TEST--
+PFA supports named placeholders
+--FILE--
+getMessage(), "\n";
+}
+
+try {
+ $d = bar(c: ?, ...);
+} catch (\Throwable $e) {
+ echo $e->getMessage(), "\n";
+}
+
+?>
+--EXPECTF--
+Closure [ static function {closure:%s:%d} ] {
+ @@ %snamed_placeholders.php 11 - 11
+
+ - Parameters [1] {
+ Parameter #0 [ $b = 2 ]
+ }
+}
+int(1)
+object(B)#%d (0) {
+}
+int(3)
+Closure [ static function {closure:%s:%d} ] {
+ @@ %snamed_placeholders.php 17 - 17
+
+ - Bound Variables [1] {
+ Variable #0 [ $fn ]
+ }
+
+ - Parameters [1] {
+ Parameter #0 [ $b = 2 ]
+ }
+}
+int(1)
+object(B)#%d (0) {
+}
+int(3)
+Closure [ static function {closure:%s:%d} ] {
+ @@ %snamed_placeholders.php 24 - 24
+
+ - Bound Variables [1] {
+ Variable #0 [ $fn ]
+ }
+
+ - Parameters [1] {
+ Parameter #0 [ $b = 2 ]
+ }
+}
+int(1)
+object(B)#%d (0) {
+}
+int(3)
+Closure [ static function {closure:%s:%d} ] {
+ @@ %snamed_placeholders.php 34 - 34
+
+ - Parameters [3] {
+ Parameter #0 [ $b = 2 ]
+ Parameter #1 [ $a = 1 ]
+ Parameter #2 [ ...$c ]
+ }
+}
+object(A)#%d (0) {
+}
+object(B)#%d (0) {
+}
+array(1) {
+ [0]=>
+ object(C)#%d (0) {
+ }
+}
+Named parameter $a overwrites previous placeholder
+Cannot use named placeholder for unknown or variadic parameter $c
diff --git a/Zend/tests/partial_application/never_cache_001.phpt b/Zend/tests/partial_application/never_cache_001.phpt
new file mode 100644
index 000000000000..3c9e8a173e51
--- /dev/null
+++ b/Zend/tests/partial_application/never_cache_001.phpt
@@ -0,0 +1,30 @@
+--TEST--
+Inline cache can not be used for ZEND_ACC_NEVER_CACHE functions
+--FILE--
+__invoke(?));
+}
+
+?>
+--EXPECT--
+string(1) "A"
+string(1) "B"
+string(1) "A"
+string(1) "B"
diff --git a/Zend/tests/partial_application/non_dynamic_call_funcs.phpt b/Zend/tests/partial_application/non_dynamic_call_funcs.phpt
new file mode 100644
index 000000000000..db25ef3dcc93
--- /dev/null
+++ b/Zend/tests/partial_application/non_dynamic_call_funcs.phpt
@@ -0,0 +1,46 @@
+--TEST--
+Functions that can not be called dynamically, can not be partially applied
+--FILE--
+getMessage(), "\n";
+ }
+}
+
+?>
+--EXPECT--
+Error: Cannot call func_get_arg() dynamically
+Error: Cannot call compact() dynamically
+Error: Cannot call extract() dynamically
+Error: Cannot call func_get_args() dynamically
+Error: Cannot call func_num_args() dynamically
+Error: Cannot call get_defined_vars() dynamically
diff --git a/Zend/tests/partial_application/observers.phpt b/Zend/tests/partial_application/observers.phpt
new file mode 100644
index 000000000000..8717b38ca326
--- /dev/null
+++ b/Zend/tests/partial_application/observers.phpt
@@ -0,0 +1,34 @@
+--TEST--
+PFA support observers
+--EXTENSIONS--
+zend_test
+--INI--
+zend_test.observer.enabled=1
+zend_test.observer.show_output=1
+zend_test.observer.observe_all=1
+--FILE--
+
+--EXPECTF--
+
+
+
+ <{closure:%s}>
+
+
+
+
+int(1)
+int(2)
+
+
+ {closure:%s:%d}>
+
diff --git a/Zend/tests/partial_application/param_reorder.phpt b/Zend/tests/partial_application/param_reorder.phpt
new file mode 100644
index 000000000000..3ade1beb0af7
--- /dev/null
+++ b/Zend/tests/partial_application/param_reorder.phpt
@@ -0,0 +1,202 @@
+--TEST--
+Named parameters define the order of parameters in a PFA
+--FILE--
+getMessage(), "\n";
+}
+
+?>
+--EXPECTF--
+# All named
+Closure [ static function {closure:%s:%d} ] {
+ @@ %sparam_reorder.php 13 - 13
+
+ - Parameters [4] {
+ Parameter #0 [ $d ]
+ Parameter #1 [ $c ]
+ Parameter #2 [ $b ]
+ Parameter #3 [ $a ]
+ }
+}
+
+array(4) {
+ [0]=>
+ int(4)
+ [1]=>
+ int(3)
+ [2]=>
+ int(2)
+ [3]=>
+ int(1)
+}
+# Some named: Positional first, then named in specified order
+Closure [ static function {closure:%s:%d} ] {
+ @@ %sparam_reorder.php 19 - 19
+
+ - Parameters [4] {
+ Parameter #0 [ $a ]
+ Parameter #1 [ $b ]
+ Parameter #2 [ $d ]
+ Parameter #3 [ $c ]
+ }
+}
+
+array(4) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(4)
+ [3]=>
+ int(3)
+}
+# Some named, one unspecified
+Closure [ static function {closure:%s:%d} ] {
+ @@ %sparam_reorder.php 25 - 25
+
+ - Parameters [3] {
+ Parameter #0 [ $a ]
+ Parameter #1 [ $c ]
+ Parameter #2 [ $b ]
+ }
+}
+
+array(4) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(3)
+ [2]=>
+ int(2)
+ [3]=>
+ NULL
+}
+# Some named, some implicit added by '...'
+Closure [ static function {closure:%s:%d} ] {
+ @@ %sparam_reorder.php 31 - 31
+
+ - Parameters [4] {
+ Parameter #0 [ $c ]
+ Parameter #1 [ $b ]
+ Parameter #2 [ $a ]
+ Parameter #3 [ $d = NULL ]
+ }
+}
+
+array(4) {
+ [0]=>
+ int(3)
+ [1]=>
+ int(2)
+ [2]=>
+ int(1)
+ [3]=>
+ int(4)
+}
+# Some named, some implicit added by '...' on variadic function
+Closure [ static function {closure:%s:%d} ] {
+ @@ %sparam_reorder.php 37 - 37
+
+ - Parameters [4] {
+ Parameter #0 [ $c ]
+ Parameter #1 [ $b ]
+ Parameter #2 [ $a ]
+ Parameter #3 [ ...$d ]
+ }
+}
+
+array(4) {
+ [0]=>
+ int(3)
+ [1]=>
+ int(2)
+ [2]=>
+ int(1)
+ [3]=>
+ array(3) {
+ [0]=>
+ int(4)
+ [1]=>
+ int(5)
+ [2]=>
+ int(6)
+ }
+}
+# Some prebound, some named
+Closure [ static function {closure:%s:%d} ] {
+ @@ %sparam_reorder.php 43 - 43
+
+ - Bound Variables [2] {
+ Variable #0 [ $a ]
+ Variable #1 [ $d ]
+ }
+
+ - Parameters [2] {
+ Parameter #0 [ $c ]
+ Parameter #1 [ $b ]
+ }
+}
+
+array(4) {
+ [0]=>
+ int(-1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(1)
+ [3]=>
+ int(-2)
+}
+# Some named, some required missing
+ArgumentCountError: f(): Argument #1 ($a) not passed
diff --git a/Zend/tests/partial_application/pipe_optimization_001.phpt b/Zend/tests/partial_application/pipe_optimization_001.phpt
new file mode 100644
index 000000000000..9610f37b76ac
--- /dev/null
+++ b/Zend/tests/partial_application/pipe_optimization_001.phpt
@@ -0,0 +1,47 @@
+--TEST--
+PFA optimization: PFA with single placeholder arg can be optimized
+--EXTENSIONS--
+opcache
+--INI--
+opcache.opt_debug_level=0x20000
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_cache=
+opcache.file_cache_only=0
+--FILE--
+ 0) {
+ function foo($a) {
+ var_dump($a);
+ }
+}
+
+1 |> foo(?);
+
+?>
+--EXPECTF--
+$_main:
+ ; (lines=9, args=0, vars=0, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_001.php:1-12
+0000 INIT_FCALL 0 %d string("time")
+0001 T1 = DO_ICALL
+0002 T0 = IS_SMALLER int(0) T1
+0003 JMPZ T0 0005
+0004 DECLARE_FUNCTION string("foo") 0
+0005 INIT_FCALL_BY_NAME 1 string("foo")
+0006 SEND_VAL_EX int(1) 1
+0007 DO_FCALL_BY_NAME
+0008 RETURN int(1)
+
+foo:
+ ; (lines=5, args=1, vars=1, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_001.php:4-6
+0000 CV0($a) = RECV 1
+0001 INIT_FCALL 1 %d string("var_dump")
+0002 SEND_VAR CV0($a) 1
+0003 DO_ICALL
+0004 RETURN null
+int(1)
diff --git a/Zend/tests/partial_application/pipe_optimization_002.phpt b/Zend/tests/partial_application/pipe_optimization_002.phpt
new file mode 100644
index 000000000000..729e70d30e6b
--- /dev/null
+++ b/Zend/tests/partial_application/pipe_optimization_002.phpt
@@ -0,0 +1,51 @@
+--TEST--
+PFA pipe optimization: PFA with only one placeholder can be optimized
+--EXTENSIONS--
+opcache
+--INI--
+opcache.opt_debug_level=0x20000
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_cache=
+opcache.file_cache_only=0
+--FILE--
+ 0) {
+ function foo($a, $b) {
+ var_dump($a, $b);
+ }
+}
+
+2 |> foo(1, ?);
+
+?>
+--EXPECTF--
+$_main:
+ ; (lines=10, args=0, vars=0, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_002.php:1-12
+0000 INIT_FCALL 0 %d string("time")
+0001 T1 = DO_ICALL
+0002 T0 = IS_SMALLER int(0) T1
+0003 JMPZ T0 0005
+0004 DECLARE_FUNCTION string("foo") 0
+0005 INIT_FCALL_BY_NAME 2 string("foo")
+0006 SEND_VAL_EX int(1) 1
+0007 SEND_VAL_EX int(2) 2
+0008 DO_FCALL_BY_NAME
+0009 RETURN int(1)
+
+foo:
+ ; (lines=7, args=2, vars=2, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_002.php:4-6
+0000 CV0($a) = RECV 1
+0001 CV1($b) = RECV 2
+0002 INIT_FCALL 2 %d string("var_dump")
+0003 SEND_VAR CV0($a) 1
+0004 SEND_VAR CV1($b) 2
+0005 DO_ICALL
+0006 RETURN null
+int(1)
+int(2)
diff --git a/Zend/tests/partial_application/pipe_optimization_003.phpt b/Zend/tests/partial_application/pipe_optimization_003.phpt
new file mode 100644
index 000000000000..da112f8f3cea
--- /dev/null
+++ b/Zend/tests/partial_application/pipe_optimization_003.phpt
@@ -0,0 +1,51 @@
+--TEST--
+PFA pipe optimization: PFA with only one placeholder can be optimized (placeholder first)
+--EXTENSIONS--
+opcache
+--INI--
+opcache.opt_debug_level=0x20000
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_cache=
+opcache.file_cache_only=0
+--FILE--
+ 0) {
+ function foo($a, $b) {
+ var_dump($a, $b);
+ }
+}
+
+2 |> foo(?, 1);
+
+?>
+--EXPECTF--
+$_main:
+ ; (lines=10, args=0, vars=0, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_003.php:1-12
+0000 INIT_FCALL 0 %d string("time")
+0001 T1 = DO_ICALL
+0002 T0 = IS_SMALLER int(0) T1
+0003 JMPZ T0 0005
+0004 DECLARE_FUNCTION string("foo") 0
+0005 INIT_FCALL_BY_NAME 2 string("foo")
+0006 SEND_VAL_EX int(2) 1
+0007 SEND_VAL_EX int(1) 2
+0008 DO_FCALL_BY_NAME
+0009 RETURN int(1)
+
+foo:
+ ; (lines=7, args=2, vars=2, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_003.php:4-6
+0000 CV0($a) = RECV 1
+0001 CV1($b) = RECV 2
+0002 INIT_FCALL 2 %d string("var_dump")
+0003 SEND_VAR CV0($a) 1
+0004 SEND_VAR CV1($b) 2
+0005 DO_ICALL
+0006 RETURN null
+int(2)
+int(1)
diff --git a/Zend/tests/partial_application/pipe_optimization_004.phpt b/Zend/tests/partial_application/pipe_optimization_004.phpt
new file mode 100644
index 000000000000..addee498d810
--- /dev/null
+++ b/Zend/tests/partial_application/pipe_optimization_004.phpt
@@ -0,0 +1,88 @@
+--TEST--
+PFA pipe optimization: PFA with multiple placeholders can not be optimized
+--EXTENSIONS--
+opcache
+--INI--
+opcache.opt_debug_level=0x20000
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_cache=
+opcache.file_cache_only=0
+--FILE--
+ 0) {
+ function foo($a, $b) {
+ var_dump($a, $b);
+ }
+}
+
+try {
+ 2 |> foo(?, ?);
+} catch (\Throwable $e) {
+ echo $e::class, ": ", $e->getMessage(), "\n";
+}
+
+?>
+--EXPECTF--
+$_main:
+ ; (lines=22, args=0, vars=1, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_004.php:1-16
+0000 INIT_FCALL 0 %d string("time")
+0001 T2 = DO_ICALL
+0002 T1 = IS_SMALLER int(0) T2
+0003 JMPZ T1 0005
+0004 DECLARE_FUNCTION string("foo") 0
+0005 INIT_FCALL_BY_NAME 2 string("foo")
+0006 SEND_PLACEHOLDER 1
+0007 SEND_PLACEHOLDER 2
+0008 T1 = CALLABLE_CONVERT_PARTIAL %d
+0009 INIT_DYNAMIC_CALL 1 T1
+0010 SEND_VAL_EX int(2) 1
+0011 DO_FCALL
+0012 RETURN int(1)
+0013 CV0($e) = CATCH string("Throwable")
+0014 T1 = FETCH_CLASS_NAME CV0($e)
+0015 ECHO T1
+0016 ECHO string(": ")
+0017 INIT_METHOD_CALL 0 CV0($e) string("getMessage")
+0018 T1 = DO_FCALL
+0019 ECHO T1
+0020 ECHO string("\n")
+0021 RETURN int(1)
+EXCEPTION TABLE:
+ 0005, 0013, -, -
+
+foo:
+ ; (lines=7, args=2, vars=2, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_004.php:4-6
+0000 CV0($a) = RECV 1
+0001 CV1($b) = RECV 2
+0002 INIT_FCALL 2 %d string("var_dump")
+0003 SEND_VAR CV0($a) 1
+0004 SEND_VAR CV1($b) 2
+0005 DO_ICALL
+0006 RETURN null
+
+$_main:
+ ; (lines=3, args=0, vars=0, tmps=%d)
+ ; (after optimizer)
+ ; %s:1-10
+0000 T0 = DECLARE_LAMBDA_FUNCTION 0
+0001 FREE T0
+0002 RETURN int(1)
+
+{closure:%s:%d}:
+ ; (lines=7, args=2, vars=2, tmps=%d)
+ ; (after optimizer)
+ ; %s:10-10
+0000 CV0($a) = RECV 1
+0001 CV1($b) = RECV 2
+0002 INIT_FCALL 2 %d string("foo")
+0003 SEND_VAR CV0($a) 1
+0004 SEND_VAR CV1($b) 2
+0005 T2 = DO_UCALL
+0006 RETURN T2
+ArgumentCountError: Too few arguments to function {closure:pfa:%s:%d}(), 1 passed in %s on line %d and exactly 2 expected
diff --git a/Zend/tests/partial_application/pipe_optimization_005.phpt b/Zend/tests/partial_application/pipe_optimization_005.phpt
new file mode 100644
index 000000000000..3ccfec836609
--- /dev/null
+++ b/Zend/tests/partial_application/pipe_optimization_005.phpt
@@ -0,0 +1,51 @@
+--TEST--
+PFA pipe optimization: PFA with only one placeholder can be optimized (variadic)
+--EXTENSIONS--
+opcache
+--INI--
+opcache.opt_debug_level=0x20000
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_cache=
+opcache.file_cache_only=0
+--FILE--
+ 0) {
+ function foo($a, $b) {
+ var_dump($a, $b);
+ }
+}
+
+2 |> foo(1, ...);
+
+?>
+--EXPECTF--
+$_main:
+ ; (lines=10, args=0, vars=0, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_005.php:1-12
+0000 INIT_FCALL 0 %d string("time")
+0001 T1 = DO_ICALL
+0002 T0 = IS_SMALLER int(0) T1
+0003 JMPZ T0 0005
+0004 DECLARE_FUNCTION string("foo") 0
+0005 INIT_FCALL_BY_NAME 2 string("foo")
+0006 SEND_VAL_EX int(1) 1
+0007 SEND_VAL_EX int(2) 2
+0008 DO_FCALL_BY_NAME
+0009 RETURN int(1)
+
+foo:
+ ; (lines=7, args=2, vars=2, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_005.php:4-6
+0000 CV0($a) = RECV 1
+0001 CV1($b) = RECV 2
+0002 INIT_FCALL 2 %d string("var_dump")
+0003 SEND_VAR CV0($a) 1
+0004 SEND_VAR CV1($b) 2
+0005 DO_ICALL
+0006 RETURN null
+int(1)
+int(2)
diff --git a/Zend/tests/partial_application/pipe_optimization_006.phpt b/Zend/tests/partial_application/pipe_optimization_006.phpt
new file mode 100644
index 000000000000..6e06477427a3
--- /dev/null
+++ b/Zend/tests/partial_application/pipe_optimization_006.phpt
@@ -0,0 +1,55 @@
+--TEST--
+PFA pipe optimization: PFA with only one placeholder can be optimized (named)
+--EXTENSIONS--
+opcache
+--INI--
+opcache.opt_debug_level=0x20000
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_cache=
+opcache.file_cache_only=0
+--FILE--
+ 0) {
+ function foo($a, $b = null, $c = null) {
+ var_dump($a, $b, $c);
+ }
+}
+
+2 |> foo(1, c: ?);
+
+?>
+--EXPECTF--
+$_main:
+ ; (lines=11, args=0, vars=0, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_006.php:1-12
+0000 INIT_FCALL 0 %d string("time")
+0001 T1 = DO_ICALL
+0002 T0 = IS_SMALLER int(0) T1
+0003 JMPZ T0 0005
+0004 DECLARE_FUNCTION string("foo") 0
+0005 INIT_FCALL_BY_NAME 1 string("foo")
+0006 SEND_VAL_EX int(1) 1
+0007 SEND_VAL_EX int(2) string("c")
+0008 CHECK_UNDEF_ARGS
+0009 DO_FCALL_BY_NAME
+0010 RETURN int(1)
+
+foo:
+ ; (lines=9, args=3, vars=3, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_006.php:4-6
+0000 CV0($a) = RECV 1
+0001 CV1($b) = RECV_INIT 2 null
+0002 CV2($c) = RECV_INIT 3 null
+0003 INIT_FCALL 3 %d string("var_dump")
+0004 SEND_VAR CV0($a) 1
+0005 SEND_VAR CV1($b) 2
+0006 SEND_VAR CV2($c) 3
+0007 DO_ICALL
+0008 RETURN null
+int(1)
+NULL
+int(2)
diff --git a/Zend/tests/partial_application/pipe_optimization_007.phpt b/Zend/tests/partial_application/pipe_optimization_007.phpt
new file mode 100644
index 000000000000..09c3c765d237
--- /dev/null
+++ b/Zend/tests/partial_application/pipe_optimization_007.phpt
@@ -0,0 +1,88 @@
+--TEST--
+PFA pipe optimization: PFA with multiple placeholders can not be optimized (named)
+--EXTENSIONS--
+opcache
+--INI--
+opcache.opt_debug_level=0x20000
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_cache=
+opcache.file_cache_only=0
+--FILE--
+ 0) {
+ function foo($a, $b) {
+ var_dump($a, $b);
+ }
+}
+
+try {
+ 2 |> foo(a: ?, b: ?);
+} catch (\Throwable $e) {
+ echo $e::class, ": ", $e->getMessage(), "\n";
+}
+
+?>
+--EXPECTF--
+$_main:
+ ; (lines=22, args=0, vars=1, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_007.php:1-16
+0000 INIT_FCALL 0 %d string("time")
+0001 T2 = DO_ICALL
+0002 T1 = IS_SMALLER int(0) T2
+0003 JMPZ T1 0005
+0004 DECLARE_FUNCTION string("foo") 0
+0005 INIT_FCALL_BY_NAME 0 string("foo")
+0006 SEND_PLACEHOLDER string("a")
+0007 SEND_PLACEHOLDER string("b")
+0008 T1 = CALLABLE_CONVERT_PARTIAL %d array(...)
+0009 INIT_DYNAMIC_CALL 1 T1
+0010 SEND_VAL_EX int(2) 1
+0011 DO_FCALL
+0012 RETURN int(1)
+0013 CV0($e) = CATCH string("Throwable")
+0014 T1 = FETCH_CLASS_NAME CV0($e)
+0015 ECHO T1
+0016 ECHO string(": ")
+0017 INIT_METHOD_CALL 0 CV0($e) string("getMessage")
+0018 T1 = DO_FCALL
+0019 ECHO T1
+0020 ECHO string("\n")
+0021 RETURN int(1)
+EXCEPTION TABLE:
+ 0005, 0013, -, -
+
+foo:
+ ; (lines=7, args=2, vars=2, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_007.php:4-6
+0000 CV0($a) = RECV 1
+0001 CV1($b) = RECV 2
+0002 INIT_FCALL 2 %d string("var_dump")
+0003 SEND_VAR CV0($a) 1
+0004 SEND_VAR CV1($b) 2
+0005 DO_ICALL
+0006 RETURN null
+
+$_main:
+ ; (lines=3, args=0, vars=0, tmps=%d)
+ ; (after optimizer)
+ ; %s:1-10
+0000 T0 = DECLARE_LAMBDA_FUNCTION 0
+0001 FREE T0
+0002 RETURN int(1)
+
+{closure:%s:%d}:
+ ; (lines=7, args=2, vars=2, tmps=%d)
+ ; (after optimizer)
+ ; %s:10-10
+0000 CV0($a) = RECV 1
+0001 CV1($b) = RECV 2
+0002 INIT_FCALL 2 %d string("foo")
+0003 SEND_VAR CV0($a) 1
+0004 SEND_VAR CV1($b) 2
+0005 T2 = DO_UCALL
+0006 RETURN T2
+ArgumentCountError: Too few arguments to function {closure:pfa:%s:%d}(), 1 passed in %s on line %d and exactly 2 expected
diff --git a/Zend/tests/partial_application/pipe_optimization_008.phpt b/Zend/tests/partial_application/pipe_optimization_008.phpt
new file mode 100644
index 000000000000..070074632c77
--- /dev/null
+++ b/Zend/tests/partial_application/pipe_optimization_008.phpt
@@ -0,0 +1,99 @@
+--TEST--
+PFA pipe optimization: PFA with both a variadic placeholder and named arg can not be optimized
+--EXTENSIONS--
+opcache
+--INI--
+opcache.opt_debug_level=0x20000
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_cache=
+opcache.file_cache_only=0
+--FILE--
+ 0) {
+ function foo($a, $b) {
+ var_dump($a, $b);
+ }
+}
+
+try {
+ 2 |> foo(a: 1, ...);
+} catch (\Throwable $e) {
+ echo $e->getMessage(), "\n";
+}
+
+?>
+--EXPECTF--
+$_main:
+ ; (lines=18, args=0, vars=1, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_008.php:1-16
+0000 INIT_FCALL 0 %d string("time")
+0001 T2 = DO_ICALL
+0002 T1 = IS_SMALLER int(0) T2
+0003 JMPZ T1 0005
+0004 DECLARE_FUNCTION string("foo") 0
+0005 INIT_FCALL_BY_NAME 0 string("foo")
+0006 SEND_VAL_EX int(1) string("a")
+0007 T1 = CALLABLE_CONVERT_PARTIAL %d
+0008 INIT_DYNAMIC_CALL 1 T1
+0009 SEND_VAL_EX int(2) 1
+0010 DO_FCALL
+0011 RETURN int(1)
+0012 CV0($e) = CATCH string("Throwable")
+0013 INIT_METHOD_CALL 0 CV0($e) string("getMessage")
+0014 T1 = DO_FCALL
+0015 ECHO T1
+0016 ECHO string("\n")
+0017 RETURN int(1)
+EXCEPTION TABLE:
+ 0005, 0012, -, -
+
+foo:
+ ; (lines=7, args=2, vars=2, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_008.php:4-6
+0000 CV0($a) = RECV 1
+0001 CV1($b) = RECV 2
+0002 INIT_FCALL 2 %d string("var_dump")
+0003 SEND_VAR CV0($a) 1
+0004 SEND_VAR CV1($b) 2
+0005 DO_ICALL
+0006 RETURN null
+
+$_main:
+ ; (lines=4, args=0, vars=1, tmps=%d)
+ ; (after optimizer)
+ ; %s:1-10
+0000 T1 = DECLARE_LAMBDA_FUNCTION 0
+0001 BIND_LEXICAL T1 CV0($a)
+0002 FREE T1
+0003 RETURN int(1)
+LIVE RANGES:
+ 1: 0001 - 0002 (tmp/var)
+
+{closure:%s:%d}:
+ ; (lines=18, args=1, vars=2, tmps=%d)
+ ; (after optimizer)
+ ; %s:10-10
+0000 CV0($b) = RECV 1
+0001 BIND_STATIC CV1($a)
+0002 T3 = FUNC_NUM_ARGS
+0003 T2 = IS_SMALLER_OR_EQUAL T3 int(1)
+0004 JMPZ T2 0010
+0005 INIT_FCALL 2 %d string("foo")
+0006 SEND_VAR CV1($a) 1
+0007 SEND_VAR CV0($b) 2
+0008 T2 = DO_UCALL
+0009 RETURN T2
+0010 INIT_FCALL 2 %d string("foo")
+0011 SEND_VAR CV1($a) 1
+0012 SEND_VAR CV0($b) 2
+0013 T2 = FUNC_GET_ARGS int(1)
+0014 SEND_UNPACK T2
+0015 CHECK_UNDEF_ARGS
+0016 T2 = DO_UCALL
+0017 RETURN T2
+int(1)
+int(2)
diff --git a/Zend/tests/partial_application/pipe_optimization_009.phpt b/Zend/tests/partial_application/pipe_optimization_009.phpt
new file mode 100644
index 000000000000..118482a3860b
--- /dev/null
+++ b/Zend/tests/partial_application/pipe_optimization_009.phpt
@@ -0,0 +1,102 @@
+--TEST--
+PFA pipe optimization: Evaluation order
+--EXTENSIONS--
+opcache
+--INI--
+opcache.opt_debug_level=0x20000
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_cache=
+opcache.file_cache_only=0
+--FILE--
+ 0) {
+ function foo($a, $b, $c) {
+ var_dump($a, $b, $c);
+ }
+ function lhs() {
+ echo __FUNCTION__, "\n";
+ return 0;
+ }
+ function arg1() {
+ echo __FUNCTION__, "\n";
+ return 1;
+ }
+ function arg2() {
+ echo __FUNCTION__, "\n";
+ return 2;
+ }
+}
+
+lhs() |> foo(arg1(), ?, arg2());
+
+?>
+--EXPECTF--
+$_main:
+ ; (lines=20, args=0, vars=0, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_009.php:1-24
+0000 INIT_FCALL 0 %d string("time")
+0001 T1 = DO_ICALL
+0002 T0 = IS_SMALLER int(0) T1
+0003 JMPZ T0 0008
+0004 DECLARE_FUNCTION string("foo") 0
+0005 DECLARE_FUNCTION string("lhs") 1
+0006 DECLARE_FUNCTION string("arg1") 2
+0007 DECLARE_FUNCTION string("arg2") 3
+0008 INIT_FCALL_BY_NAME 0 string("lhs")
+0009 T0 = DO_FCALL_BY_NAME
+0010 INIT_FCALL_BY_NAME 3 string("foo")
+0011 INIT_FCALL_BY_NAME 0 string("arg1")
+0012 V1 = DO_FCALL_BY_NAME
+0013 SEND_VAR_NO_REF_EX V1 1
+0014 SEND_VAL_EX T0 2
+0015 INIT_FCALL_BY_NAME 0 string("arg2")
+0016 V0 = DO_FCALL_BY_NAME
+0017 SEND_VAR_NO_REF_EX V0 3
+0018 DO_FCALL_BY_NAME
+0019 RETURN int(1)
+LIVE RANGES:
+ 0: 0010 - 0014 (tmp/var)
+
+foo:
+ ; (lines=9, args=3, vars=3, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_009.php:4-6
+0000 CV0($a) = RECV 1
+0001 CV1($b) = RECV 2
+0002 CV2($c) = RECV 3
+0003 INIT_FCALL 3 %d string("var_dump")
+0004 SEND_VAR CV0($a) 1
+0005 SEND_VAR CV1($b) 2
+0006 SEND_VAR CV2($c) 3
+0007 DO_ICALL
+0008 RETURN null
+
+lhs:
+ ; (lines=2, args=0, vars=0, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_009.php:7-10
+0000 ECHO string("lhs\n")
+0001 RETURN int(0)
+
+arg1:
+ ; (lines=2, args=0, vars=0, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_009.php:11-14
+0000 ECHO string("arg1\n")
+0001 RETURN int(1)
+
+arg2:
+ ; (lines=2, args=0, vars=0, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_009.php:15-18
+0000 ECHO string("arg2\n")
+0001 RETURN int(2)
+lhs
+arg1
+arg2
+int(1)
+int(0)
+int(2)
diff --git a/Zend/tests/partial_application/pipe_optimization_010.phpt b/Zend/tests/partial_application/pipe_optimization_010.phpt
new file mode 100644
index 000000000000..f77c2a97732e
--- /dev/null
+++ b/Zend/tests/partial_application/pipe_optimization_010.phpt
@@ -0,0 +1,58 @@
+--TEST--
+PFA pipe optimization: References
+--EXTENSIONS--
+opcache
+--INI--
+opcache.opt_debug_level=0x20000
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_cache=
+opcache.file_cache_only=0
+--FILE--
+ 0) {
+ function foo(&$a, $b) {
+ var_dump($a, $b);
+ $a = 2;
+ }
+}
+
+1 |> foo($a, ?);
+var_dump($a);
+
+?>
+--EXPECTF--
+$_main:
+ ; (lines=13, args=0, vars=1, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_010.php:1-14
+0000 INIT_FCALL 0 %d string("time")
+0001 T2 = DO_ICALL
+0002 T1 = IS_SMALLER int(0) T2
+0003 JMPZ T1 0005
+0004 DECLARE_FUNCTION string("foo") 0
+0005 INIT_FCALL_BY_NAME 2 string("foo")
+0006 SEND_VAR_EX CV0($a) 1
+0007 SEND_VAL_EX int(1) 2
+0008 DO_FCALL_BY_NAME
+0009 INIT_FCALL 1 %d string("var_dump")
+0010 SEND_VAR CV0($a) 1
+0011 DO_ICALL
+0012 RETURN int(1)
+
+foo:
+ ; (lines=8, args=2, vars=2, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_010.php:4-7
+0000 CV0($a) = RECV 1
+0001 CV1($b) = RECV 2
+0002 INIT_FCALL 2 %d string("var_dump")
+0003 SEND_VAR CV0($a) 1
+0004 SEND_VAR CV1($b) 2
+0005 DO_ICALL
+0006 ASSIGN CV0($a) int(2)
+0007 RETURN null
+NULL
+int(1)
+int(2)
diff --git a/Zend/tests/partial_application/pipe_optimization_011.phpt b/Zend/tests/partial_application/pipe_optimization_011.phpt
new file mode 100644
index 000000000000..cd1c986d99e7
--- /dev/null
+++ b/Zend/tests/partial_application/pipe_optimization_011.phpt
@@ -0,0 +1,98 @@
+--TEST--
+PFA pipe optimization: Evaluation order
+--EXTENSIONS--
+opcache
+--INI--
+opcache.opt_debug_level=0x20000
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_cache=
+opcache.file_cache_only=0
+--FILE--
+ 0) {
+ function foo($a, $b, $c) {
+ var_dump($a, $b, $c);
+ }
+ function arg1() {
+ global $a;
+ $a = 2;
+ echo __FUNCTION__, "\n";
+ return 1;
+ }
+ function arg2() {
+ global $a;
+ $a = 3;
+ echo __FUNCTION__, "\n";
+ return 2;
+ }
+}
+
+$a = 0;
+$a |> foo(arg1(), ?, arg2());
+
+?>
+--EXPECTF--
+$_main:
+ ; (lines=19, args=0, vars=1, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_011.php:1-25
+0000 INIT_FCALL 0 %d string("time")
+0001 T2 = DO_ICALL
+0002 T1 = IS_SMALLER int(0) T2
+0003 JMPZ T1 0007
+0004 DECLARE_FUNCTION string("foo") 0
+0005 DECLARE_FUNCTION string("arg1") %d
+0006 DECLARE_FUNCTION string("arg2") %d
+0007 ASSIGN CV0($a) int(0)
+0008 T1 = QM_ASSIGN CV0($a)
+0009 INIT_FCALL_BY_NAME 3 string("foo")
+0010 INIT_FCALL_BY_NAME 0 string("arg1")
+0011 V2 = DO_FCALL_BY_NAME
+0012 SEND_VAR_NO_REF_EX V2 1
+0013 SEND_VAL_EX T1 2
+0014 INIT_FCALL_BY_NAME 0 string("arg2")
+0015 V1 = DO_FCALL_BY_NAME
+0016 SEND_VAR_NO_REF_EX V1 3
+0017 DO_FCALL_BY_NAME
+0018 RETURN int(1)
+LIVE RANGES:
+ 1: 0009 - 0013 (tmp/var)
+
+foo:
+ ; (lines=9, args=3, vars=3, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_011.php:4-6
+0000 CV0($a) = RECV 1
+0001 CV1($b) = RECV 2
+0002 CV2($c) = RECV 3
+0003 INIT_FCALL 3 %d string("var_dump")
+0004 SEND_VAR CV0($a) 1
+0005 SEND_VAR CV1($b) 2
+0006 SEND_VAR CV2($c) 3
+0007 DO_ICALL
+0008 RETURN null
+
+arg1:
+ ; (lines=4, args=0, vars=1, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_011.php:7-12
+0000 BIND_GLOBAL CV0($a) string("a")
+0001 ASSIGN CV0($a) int(2)
+0002 ECHO string("arg1\n")
+0003 RETURN int(1)
+
+arg2:
+ ; (lines=4, args=0, vars=1, tmps=%d)
+ ; (after optimizer)
+ ; %spipe_optimization_011.php:13-18
+0000 BIND_GLOBAL CV0($a) string("a")
+0001 ASSIGN CV0($a) int(3)
+0002 ECHO string("arg2\n")
+0003 RETURN int(2)
+arg1
+arg2
+int(1)
+int(0)
+int(2)
diff --git a/Zend/tests/partial_application/pipe_optimization_012.phpt b/Zend/tests/partial_application/pipe_optimization_012.phpt
new file mode 100644
index 000000000000..da172874adce
--- /dev/null
+++ b/Zend/tests/partial_application/pipe_optimization_012.phpt
@@ -0,0 +1,52 @@
+--TEST--
+PFA optimization: PFA with named args and placeholders can be optimized
+--EXTENSIONS--
+opcache
+--INI--
+opcache.opt_debug_level=0x20000
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_cache=
+opcache.file_cache_only=0
+--FILE--
+ 0) {
+ function foo($a, $b) {
+ var_dump($a, $b);
+ }
+}
+
+1 |> foo(?, b: 2);
+
+?>
+--EXPECTF--
+$_main:
+ ; (lines=11, args=0, vars=0, tmps=%d)
+ ; (after optimizer)
+ ; %s:1-12
+0000 INIT_FCALL 0 %d string("time")
+0001 T1 = DO_ICALL
+0002 T0 = IS_SMALLER int(0) T1
+0003 JMPZ T0 0005
+0004 DECLARE_FUNCTION string("foo") 0
+0005 INIT_FCALL_BY_NAME 1 string("foo")
+0006 SEND_VAL_EX int(1) 1
+0007 SEND_VAL_EX int(2) string("b")
+0008 CHECK_UNDEF_ARGS
+0009 DO_FCALL_BY_NAME
+0010 RETURN int(1)
+
+foo:
+ ; (lines=7, args=2, vars=2, tmps=%d)
+ ; (after optimizer)
+ ; %s:4-6
+0000 CV0($a) = RECV 1
+0001 CV1($b) = RECV 2
+0002 INIT_FCALL 2 %d string("var_dump")
+0003 SEND_VAR CV0($a) 1
+0004 SEND_VAR CV1($b) 2
+0005 DO_ICALL
+0006 RETURN null
+int(1)
+int(2)
diff --git a/Zend/tests/partial_application/pipe_optimization_013.phpt b/Zend/tests/partial_application/pipe_optimization_013.phpt
new file mode 100644
index 000000000000..7d1a48b2f2ed
--- /dev/null
+++ b/Zend/tests/partial_application/pipe_optimization_013.phpt
@@ -0,0 +1,87 @@
+--TEST--
+PFA optimization: PFA with named args and a variadic placeholder can not be optimized
+--EXTENSIONS--
+opcache
+--INI--
+opcache.opt_debug_level=0x20000
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_cache=
+opcache.file_cache_only=0
+--FILE--
+ 0) {
+ function foo($a, $b) {
+ var_dump($a, $b);
+ }
+}
+
+1 |> foo(b: 2, ...);
+
+?>
+--EXPECTF--
+$_main:
+ ; (lines=12, args=0, vars=0, tmps=%d)
+ ; (after optimizer)
+ ; %s:1-12
+0000 INIT_FCALL 0 %d string("time")
+0001 T1 = DO_ICALL
+0002 T0 = IS_SMALLER int(0) T1
+0003 JMPZ T0 0005
+0004 DECLARE_FUNCTION string("foo") 0
+0005 INIT_FCALL_BY_NAME 0 string("foo")
+0006 SEND_VAL_EX int(2) string("b")
+0007 T0 = CALLABLE_CONVERT_PARTIAL 3
+0008 INIT_DYNAMIC_CALL 1 T0
+0009 SEND_VAL_EX int(1) 1
+0010 DO_FCALL
+0011 RETURN int(1)
+
+foo:
+ ; (lines=7, args=2, vars=2, tmps=%d)
+ ; (after optimizer)
+ ; %s:4-6
+0000 CV0($a) = RECV 1
+0001 CV1($b) = RECV 2
+0002 INIT_FCALL 2 %d string("var_dump")
+0003 SEND_VAR CV0($a) 1
+0004 SEND_VAR CV1($b) 2
+0005 DO_ICALL
+0006 RETURN null
+
+$_main:
+ ; (lines=4, args=0, vars=1, tmps=%d)
+ ; (after optimizer)
+ ; %s:1-9
+0000 T1 = DECLARE_LAMBDA_FUNCTION 0
+0001 BIND_LEXICAL T1 CV0($b)
+0002 FREE T1
+0003 RETURN int(1)
+LIVE RANGES:
+ 1: 0001 - 0002 (tmp/var)
+
+{closure:pfa:%s:9}:
+ ; (lines=18, args=1, vars=2, tmps=%d)
+ ; (after optimizer)
+ ; %s:9-9
+0000 CV0($a) = RECV 1
+0001 BIND_STATIC CV1($b)
+0002 T3 = FUNC_NUM_ARGS
+0003 T2 = IS_SMALLER_OR_EQUAL T3 int(1)
+0004 JMPZ T2 0010
+0005 INIT_FCALL 2 %d string("foo")
+0006 SEND_VAR CV0($a) 1
+0007 SEND_VAR CV1($b) 2
+0008 T2 = DO_UCALL
+0009 RETURN T2
+0010 INIT_FCALL 2 %d string("foo")
+0011 SEND_VAR CV0($a) 1
+0012 SEND_VAR CV1($b) 2
+0013 T2 = FUNC_GET_ARGS int(1)
+0014 SEND_UNPACK T2
+0015 CHECK_UNDEF_ARGS
+0016 T2 = DO_UCALL
+0017 RETURN T2
+int(1)
+int(2)
diff --git a/Zend/tests/partial_application/pipe_optimization_014.phpt b/Zend/tests/partial_application/pipe_optimization_014.phpt
new file mode 100644
index 000000000000..6e66d7e0e99d
--- /dev/null
+++ b/Zend/tests/partial_application/pipe_optimization_014.phpt
@@ -0,0 +1,68 @@
+--TEST--
+PFA pipe optimization: PFA with unknown named parameter can be optimized
+--EXTENSIONS--
+opcache
+--INI--
+opcache.opt_debug_level=0x20000
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_cache=
+opcache.file_cache_only=0
+--FILE--
+ 0) {
+ function foo($a, $b = null, $c = null) {
+ var_dump($a, $b, $c);
+ }
+}
+
+try {
+ 2 |> foo(1, unknown: ?);
+} catch (Error $e) {
+ echo $e::class, ": ", $e->getMessage(), "\n";
+}
+
+?>
+--EXPECTF--
+$_main:
+ ; (lines=20, args=0, vars=1, tmps=%d)
+ ; (after optimizer)
+ ; %s:1-16
+0000 INIT_FCALL 0 %d string("time")
+0001 T2 = DO_ICALL
+0002 T1 = IS_SMALLER int(0) T2
+0003 JMPZ T1 0005
+0004 DECLARE_FUNCTION string("foo") 0
+0005 INIT_FCALL_BY_NAME 1 string("foo")
+0006 SEND_VAL_EX int(1) 1
+0007 SEND_VAL_EX int(2) string("unknown")
+0008 CHECK_UNDEF_ARGS
+0009 DO_FCALL_BY_NAME
+0010 RETURN int(1)
+0011 CV0($e) = CATCH string("Error")
+0012 T1 = FETCH_CLASS_NAME CV0($e)
+0013 ECHO T1
+0014 ECHO string(": ")
+0015 INIT_METHOD_CALL 0 CV0($e) string("getMessage")
+0016 T1 = DO_FCALL
+0017 ECHO T1
+0018 ECHO string("\n")
+0019 RETURN int(1)
+EXCEPTION TABLE:
+ 0005, 0011, -, -
+
+foo:
+ ; (lines=9, args=3, vars=3, tmps=%d)
+ ; (after optimizer)
+ ; %s:4-6
+0000 CV0($a) = RECV 1
+0001 CV1($b) = RECV_INIT 2 null
+0002 CV2($c) = RECV_INIT 3 null
+0003 INIT_FCALL 3 %d string("var_dump")
+0004 SEND_VAR CV0($a) 1
+0005 SEND_VAR CV1($b) 2
+0006 SEND_VAR CV2($c) 3
+0007 DO_ICALL
+0008 RETURN null
+Error: Unknown named parameter $unknown
diff --git a/Zend/tests/partial_application/pipe_optimization_015.phpt b/Zend/tests/partial_application/pipe_optimization_015.phpt
new file mode 100644
index 000000000000..ce293c7a300c
--- /dev/null
+++ b/Zend/tests/partial_application/pipe_optimization_015.phpt
@@ -0,0 +1,55 @@
+--TEST--
+PFA pipe optimization: PFA with skipped optional parameter can be optimized
+--EXTENSIONS--
+opcache
+--INI--
+opcache.opt_debug_level=0x20000
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_cache=
+opcache.file_cache_only=0
+--FILE--
+ 0) {
+ function foo($a, $b = null, $c = null) {
+ var_dump($a, $b, $c);
+ }
+}
+
+3 |> foo(1, c: ?);
+
+?>
+--EXPECTF--
+$_main:
+ ; (lines=11, args=0, vars=0, tmps=%d)
+ ; (after optimizer)
+ ; %s:1-12
+0000 INIT_FCALL 0 %d string("time")
+0001 T1 = DO_ICALL
+0002 T0 = IS_SMALLER int(0) T1
+0003 JMPZ T0 0005
+0004 DECLARE_FUNCTION string("foo") 0
+0005 INIT_FCALL_BY_NAME 1 string("foo")
+0006 SEND_VAL_EX int(1) 1
+0007 SEND_VAL_EX int(3) string("c")
+0008 CHECK_UNDEF_ARGS
+0009 DO_FCALL_BY_NAME
+0010 RETURN int(1)
+
+foo:
+ ; (lines=9, args=3, vars=3, tmps=%d)
+ ; (after optimizer)
+ ; %s:4-6
+0000 CV0($a) = RECV 1
+0001 CV1($b) = RECV_INIT 2 null
+0002 CV2($c) = RECV_INIT 3 null
+0003 INIT_FCALL 3 %d string("var_dump")
+0004 SEND_VAR CV0($a) 1
+0005 SEND_VAR CV1($b) 2
+0006 SEND_VAR CV2($c) 3
+0007 DO_ICALL
+0008 RETURN null
+int(1)
+NULL
+int(3)
diff --git a/Zend/tests/partial_application/preloading.inc b/Zend/tests/partial_application/preloading.inc
new file mode 100644
index 000000000000..885ed0c5b0f1
--- /dev/null
+++ b/Zend/tests/partial_application/preloading.inc
@@ -0,0 +1,13 @@
+
diff --git a/Zend/tests/partial_application/preloading.phpt b/Zend/tests/partial_application/preloading.phpt
new file mode 100644
index 000000000000..23ad6edf2c4c
--- /dev/null
+++ b/Zend/tests/partial_application/preloading.phpt
@@ -0,0 +1,19 @@
+--TEST--
+PFA preloading
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.preload={PWD}/preloading.inc
+--SKIPIF--
+
+--FILE--
+
+--EXPECT--
+int(2)
+int(2)
diff --git a/Zend/tests/partial_application/rebinding_001.phpt b/Zend/tests/partial_application/rebinding_001.phpt
new file mode 100644
index 000000000000..d1913957a8c9
--- /dev/null
+++ b/Zend/tests/partial_application/rebinding_001.phpt
@@ -0,0 +1,59 @@
+--TEST--
+PFA can only be rebound to an instanceof $this
+--FILE--
+f(?);
+$g = $c->g(?);
+
+echo "# Can be rebound to \$this of the same class:\n";
+$f->bindTo(new C)(1);
+
+echo "# Can be rebound to \$this of a sub-class:\n";
+$f->bindTo(new SubClass)(1);
+
+echo "# Cannot be rebound to an unrelated class:\n";
+try {
+ $f->bindTo(new Unrelated)(1);
+} catch (Error $e) {
+ echo $e::class, ": ", $e->getMessage(), "\n";
+}
+
+echo "# Cannot unbind \$this on instance method:\n";
+try {
+ $f->bindTo(null)(1);
+} catch (Error $e) {
+ echo $e::class, ": ", $e->getMessage(), "\n";
+}
+
+echo "# Can unbind \$this on static method:\n";
+$g->bindTo(null)(1);
+
+?>
+--EXPECTF--
+# Can be rebound to $this of the same class:
+object(C)#%d (0) {
+}
+# Can be rebound to $this of a sub-class:
+object(SubClass)#%d (0) {
+}
+# Cannot be rebound to an unrelated class:
+
+Warning: Cannot bind method C::{closure:%s:%d}() to object of class Unrelated, this will be an error in PHP 9 in %s on line %d
+Error: Value of type null is not callable
+# Cannot unbind $this on instance method:
+
+Warning: Cannot unbind $this of method, this will be an error in PHP 9 in %s on line %d
+Error: Value of type null is not callable
+# Can unbind $this on static method:
+string(1) "C"
diff --git a/Zend/tests/partial_application/rebinding_002.phpt b/Zend/tests/partial_application/rebinding_002.phpt
new file mode 100644
index 000000000000..25e938120676
--- /dev/null
+++ b/Zend/tests/partial_application/rebinding_002.phpt
@@ -0,0 +1,45 @@
+--TEST--
+PFA scope cannot be rebound
+--FILE--
+f(?);
+$g = g(?);
+
+echo "# Can be rebound to the same scope:\n";
+$f->bindTo($c, C::class)(1);
+
+echo "# Method cannot be rebound to a different scope:\n";
+try {
+ $f->bindTo($c, SubClass::class)(1);
+} catch (Error $e) {
+ echo $e->getMessage(), "\n";
+}
+
+echo "# Function cannot be rebound to a different scope:\n";
+try {
+ $g->bindTo($c, SubClass::class)(1);
+} catch (Error $e) {
+ echo $e->getMessage(), "\n";
+}
+?>
+--EXPECTF--
+# Can be rebound to the same scope:
+string(1) "C"
+# Method cannot be rebound to a different scope:
+
+Warning: Cannot rebind scope of closure created from method, this will be an error in PHP 9 in %s on line %d
+Value of type null is not callable
+# Function cannot be rebound to a different scope:
+
+Warning: Cannot bind an instance to a static closure, this will be an error in PHP 9 in %s on line %d
+Value of type null is not callable
diff --git a/Zend/tests/partial_application/rebinding_003.phpt b/Zend/tests/partial_application/rebinding_003.phpt
new file mode 100644
index 000000000000..9417bbc2d320
--- /dev/null
+++ b/Zend/tests/partial_application/rebinding_003.phpt
@@ -0,0 +1,69 @@
+--TEST--
+Rebinding PFA of Closure rebinds inner Closure
+--FILE--
+getF()(?);
+$g = $c->getG()(?);
+
+echo "# Can be rebound to \$this of the same class:\n";
+$d = new C();
+$f->bindTo($d)($d);
+
+echo "# Can be rebound to \$this of a sub-class:\n";
+$d = new SubClass();
+$f->bindTo($d)($d);
+
+echo "# Cannot be rebound to an unrelated class:\n";
+try {
+ $f->bindTo(new Unrelated)($c);
+} catch (Error $e) {
+ echo $e::class, ": ", $e->getMessage(), "\n";
+}
+
+echo "# Cannot unbind \$this on non-static closure:\n";
+try {
+ $f->bindTo(null)($c);
+} catch (Error $e) {
+ echo $e::class, ": ", $e->getMessage(), "\n";
+}
+
+echo "# Can unbind \$this on static closure:\n";
+$g->bindTo(null)($c);
+
+?>
+--EXPECTF--
+# Can be rebound to $this of the same class:
+object(C)#%d (0) {
+}
+bool(true)
+# Can be rebound to $this of a sub-class:
+object(SubClass)#%d (0) {
+}
+bool(true)
+# Cannot be rebound to an unrelated class:
+
+Warning: Cannot bind method C::{closure:%s:%d}() to object of class Unrelated, this will be an error in PHP 9 in %s on line %d
+Error: Value of type null is not callable
+# Cannot unbind $this on non-static closure:
+
+Warning: Cannot unbind $this of method, this will be an error in PHP 9 in %s on line %d
+Error: Value of type null is not callable
+# Can unbind $this on static closure:
+string(1) "C"
+object(C)#%d (0) {
+}
diff --git a/Zend/tests/partial_application/recorded_warnings.phpt b/Zend/tests/partial_application/recorded_warnings.phpt
new file mode 100644
index 000000000000..f25be826f525
--- /dev/null
+++ b/Zend/tests/partial_application/recorded_warnings.phpt
@@ -0,0 +1,14 @@
+--TEST--
+PFA compilation warnings are recorded and replayed
+--FILE--
+
+--EXPECTF--
+Deprecated: Using "_" as a type name is deprecated since 8.4 in %s on line 3
+
+Deprecated: Using "_" as a type name is deprecated since 8.4 in %s on line 5
diff --git a/Zend/tests/partial_application/references_001.phpt b/Zend/tests/partial_application/references_001.phpt
new file mode 100644
index 000000000000..080b3085acc0
--- /dev/null
+++ b/Zend/tests/partial_application/references_001.phpt
@@ -0,0 +1,24 @@
+--TEST--
+PFA receives by val if the actual function does
+--FILE--
+
+--EXPECT--
+array(1) {
+ [0]=>
+ &string(49) "unchanged because foo() doesn't take by reference"
+}
+string(49) "unchanged because foo() doesn't take by reference"
diff --git a/Zend/tests/partial_application/references_002.phpt b/Zend/tests/partial_application/references_002.phpt
new file mode 100644
index 000000000000..42a90648c1ae
--- /dev/null
+++ b/Zend/tests/partial_application/references_002.phpt
@@ -0,0 +1,24 @@
+--TEST--
+PFA receives by ref if the actual function does
+--FILE--
+
+--EXPECT--
+array(1) {
+ [0]=>
+ &int(2)
+}
+int(2)
diff --git a/Zend/tests/partial_application/references_003.phpt b/Zend/tests/partial_application/references_003.phpt
new file mode 100644
index 000000000000..be116b06c79f
--- /dev/null
+++ b/Zend/tests/partial_application/references_003.phpt
@@ -0,0 +1,20 @@
+--TEST--
+PFA receives by ref if the actual function does
+--FILE--
+getMessage(), "\n";
+}
+
+?>
+--EXPECTF--
+{closure:%s}(): Argument #1 ($b) could not be passed by reference
diff --git a/Zend/tests/partial_application/references_004.phpt b/Zend/tests/partial_application/references_004.phpt
new file mode 100644
index 000000000000..8ef3ff002ce7
--- /dev/null
+++ b/Zend/tests/partial_application/references_004.phpt
@@ -0,0 +1,42 @@
+--TEST--
+PFA receives variadic param by ref if the actual function does
+--FILE--
+
+--EXPECTF--
+Closure [ static function {closure:%s:%d} ] {
+ @@ %sreferences_004.php 13 - 13
+
+ - Bound Variables [2] {
+ Variable #0 [ $a ]
+ Variable #1 [ $args1 ]
+ }
+
+ - Parameters [2] {
+ Parameter #0 [ &$args0 ]
+ Parameter #1 [ &...$args ]
+ }
+}
+
+int(-2)
+int(-3)
+int(-4)
diff --git a/Zend/tests/partial_application/references_005.phpt b/Zend/tests/partial_application/references_005.phpt
new file mode 100644
index 000000000000..e8c7c27a07be
--- /dev/null
+++ b/Zend/tests/partial_application/references_005.phpt
@@ -0,0 +1,26 @@
+--TEST--
+PFA inherits return by ref
+--FILE--
+
+--EXPECT--
+array(1) {
+ [0]=>
+ int(1)
+}
+array(1) {
+ [0]=>
+ int(1)
+}
diff --git a/Zend/tests/partial_application/reflection_001.phpt b/Zend/tests/partial_application/reflection_001.phpt
new file mode 100644
index 000000000000..f101bc3348e0
--- /dev/null
+++ b/Zend/tests/partial_application/reflection_001.phpt
@@ -0,0 +1,48 @@
+--TEST--
+PFA reflection: optional parameters
+--FILE--
+
+--EXPECTF--
+Closure [ static function {closure:%s:%d} ] {
+ @@ %sreflection_001.php 6 - 6
+
+ - Parameters [3] {
+ Parameter #0 [ $a = 1 ]
+ Parameter #1 [ $b = 5 ]
+ Parameter #2 [ $c = 10 ]
+ }
+}
+Closure [ static function {closure:%s:%d} ] {
+ @@ %sreflection_001.php 10 - 10
+
+ - Parameters [3] {
+ Parameter #0 [ $a = 1 ]
+ Parameter #1 [ $b = 5 ]
+ Parameter #2 [ $c = 10 ]
+ }
+}
+Closure [ static function {closure:%s:%d} ] {
+ @@ %sreflection_001.php 14 - 14
+
+ - Parameters [3] {
+ Parameter #0 [ $a = 1 ]
+ Parameter #1 [ $b = 5 ]
+ Parameter #2 [ $c = 10 ]
+ }
+}
diff --git a/Zend/tests/partial_application/reflection_002.phpt b/Zend/tests/partial_application/reflection_002.phpt
new file mode 100644
index 000000000000..da91a7af50cf
--- /dev/null
+++ b/Zend/tests/partial_application/reflection_002.phpt
@@ -0,0 +1,57 @@
+--TEST--
+PFA reflection: variadics
+--FILE--
+
+--EXPECTF--
+Closure [ static function {closure:%s:%d} ] {
+ @@ %s 6 - 6
+
+ - Parameters [1] {
+ Parameter #0 [ $a ]
+ }
+}
+Closure [ static function {closure:%s:%d} ] {
+ @@ %s 10 - 10
+
+ - Parameters [2] {
+ Parameter #0 [ $a ]
+ Parameter #1 [ ...$b ]
+ }
+}
+Closure [ static function {closure:%s:%d} ] {
+ @@ %s 14 - 14
+
+ - Parameters [2] {
+ Parameter #0 [ $a ]
+ Parameter #1 [ $b0 ]
+ }
+}
+Closure [ static function {closure:%s:%d} ] {
+ @@ %s 18 - 18
+
+ - Parameters [3] {
+ Parameter #0 [ $a ]
+ Parameter #1 [ $b0 ]
+ Parameter #2 [ $b1 ]
+ }
+}
diff --git a/Zend/tests/partial_application/reflection_003.phpt b/Zend/tests/partial_application/reflection_003.phpt
new file mode 100644
index 000000000000..90506d38a778
--- /dev/null
+++ b/Zend/tests/partial_application/reflection_003.phpt
@@ -0,0 +1,43 @@
+--TEST--
+PFA reflection: internal with variadics
+--FILE--
+
+--EXPECTF--
+Closure [ static function {closure:%s:%d} ] {
+ @@ %sreflection_003.php 2 - 2
+
+ - Parameters [1] {
+ Parameter #0 [ string $format ]
+ }
+ - Return [ string ]
+}
+Closure [ static function {closure:%s:%d} ] {
+ @@ %sreflection_003.php 6 - 6
+
+ - Parameters [2] {
+ Parameter #0 [ string $format ]
+ Parameter #1 [ mixed ...$values ]
+ }
+ - Return [ string ]
+}
+Closure [ static function {closure:%s:%d} ] {
+ @@ %sreflection_003.php 10 - 10
+
+ - Parameters [2] {
+ Parameter #0 [ string $format ]
+ Parameter #1 [ mixed $values0 ]
+ }
+ - Return [ string ]
+}
diff --git a/Zend/tests/partial_application/reflection_004.phpt b/Zend/tests/partial_application/reflection_004.phpt
new file mode 100644
index 000000000000..7226383f5afa
--- /dev/null
+++ b/Zend/tests/partial_application/reflection_004.phpt
@@ -0,0 +1,16 @@
+--TEST--
+PFA reflection: ReflectionFunction::isAnonymous() is true for partials
+--FILE--
+isAnonymous());
+
+var_dump((new ReflectionFunction(function () {}))->isAnonymous());
+
+var_dump((new ReflectionFunction(sprintf(?)))->isAnonymous());
+
+?>
+--EXPECT--
+bool(false)
+bool(true)
+bool(true)
diff --git a/Zend/tests/partial_application/reflection_005.phpt b/Zend/tests/partial_application/reflection_005.phpt
new file mode 100644
index 000000000000..be86270c004c
--- /dev/null
+++ b/Zend/tests/partial_application/reflection_005.phpt
@@ -0,0 +1,16 @@
+--TEST--
+PFA reflection: ReflectionFunction::isClosure() is true for partials
+--FILE--
+isClosure());
+
+var_dump((new ReflectionFunction(function () {}))->isClosure());
+
+var_dump((new ReflectionFunction(sprintf(?)))->isClosure());
+
+?>
+--EXPECT--
+bool(false)
+bool(true)
+bool(true)
diff --git a/Zend/tests/partial_application/relative_return_types.phpt b/Zend/tests/partial_application/relative_return_types.phpt
new file mode 100644
index 000000000000..5729f7edfd02
--- /dev/null
+++ b/Zend/tests/partial_application/relative_return_types.phpt
@@ -0,0 +1,148 @@
+--TEST--
+PFA supports relative return types
+--FILE--
+ 0) {
+ trait T {
+ public function getSelf(object $o): self {
+ return $o;
+ }
+ public function getStatic(object $o): static {
+ return $o;
+ }
+ }
+}
+
+class C {
+ use T;
+}
+
+class D extends C {
+}
+
+$c = new C;
+
+echo "# C::getSelf():\n";
+
+$self = $c->getSelf(?);
+
+echo (string) new ReflectionFunction($self), "\n";
+
+var_dump($self($c));
+var_dump($self(new D));
+try {
+ $self(new stdClass);
+} catch (Error $e) {
+ echo $e->getMessage(), "\n";
+}
+
+echo "# C::getStatic():\n";
+
+$static = $c->getStatic(?);
+
+echo (string) new ReflectionFunction($static), "\n";
+
+var_dump($static($c));
+var_dump($static(new D));
+try {
+ $static(new stdClass);
+} catch (Error $e) {
+ echo $e->getMessage(), "\n";
+}
+
+$d = new D;
+
+echo "# D::getSelf():\n";
+
+$self = $d->getSelf(?);
+
+echo (string) new ReflectionFunction($self), "\n";
+
+var_dump($self($d));
+var_dump($self(new C));
+try {
+ $self(new stdClass);
+} catch (Error $e) {
+ echo $e::class, ": ", $e->getMessage(), "\n";
+}
+
+echo "# D::getStatic():\n";
+
+$static = $d->getStatic(?);
+
+echo (string) new ReflectionFunction($static), "\n";
+
+var_dump($static($d));
+try {
+ var_dump($static(new C));
+} catch (Error $e) {
+ echo $e::class, ": ", $e->getMessage(), "\n";
+}
+try {
+ $static(new stdClass);
+} catch (Error $e) {
+ echo $e->getMessage(), "\n";
+}
+
+?>
+--EXPECTF--
+# C::getSelf():
+Closure [ public method {closure:%s:%d} ] {
+ @@ %s 25 - 25
+
+ - Parameters [1] {
+ Parameter #0 [ object $o ]
+ }
+ - Return [ self ]
+}
+
+object(C)#%d (0) {
+}
+object(D)#%d (0) {
+}
+C::getSelf(): Return value must be of type C, stdClass returned
+# C::getStatic():
+Closure [ public method {closure:%s:%d} ] {
+ @@ %s 39 - 39
+
+ - Parameters [1] {
+ Parameter #0 [ object $o ]
+ }
+ - Return [ static ]
+}
+
+object(C)#%d (0) {
+}
+object(D)#%d (0) {
+}
+C::getStatic(): Return value must be of type C, stdClass returned
+# D::getSelf():
+Closure [ public method {closure:%s:%d} ] {
+ @@ %s 55 - 55
+
+ - Parameters [1] {
+ Parameter #0 [ object $o ]
+ }
+ - Return [ self ]
+}
+
+object(D)#%d (0) {
+}
+object(C)#%d (0) {
+}
+TypeError: C::getSelf(): Return value must be of type C, stdClass returned
+# D::getStatic():
+Closure [ public method {closure:%s:%d} ] {
+ @@ %s 69 - 69
+
+ - Parameters [1] {
+ Parameter #0 [ object $o ]
+ }
+ - Return [ static ]
+}
+
+object(D)#%d (0) {
+}
+TypeError: C::getStatic(): Return value must be of type D, C returned
+C::getStatic(): Return value must be of type D, stdClass returned
diff --git a/Zend/tests/partial_application/return_type.phpt b/Zend/tests/partial_application/return_type.phpt
new file mode 100644
index 000000000000..ae3738e2c660
--- /dev/null
+++ b/Zend/tests/partial_application/return_type.phpt
@@ -0,0 +1,20 @@
+--TEST--
+PFA inherits return type
+--FILE--
+
+--EXPECTF--
+Closure [ static function {closure:%s:%d} ] {
+ @@ %s 4 - 4
+
+ - Bound Variables [1] {
+ Variable #0 [ $a ]
+ }
+
+ - Parameters [0] {
+ }
+ - Return [ array ]
+}
diff --git a/Zend/tests/partial_application/rfc_examples.inc b/Zend/tests/partial_application/rfc_examples.inc
new file mode 100644
index 000000000000..53babc07888b
--- /dev/null
+++ b/Zend/tests/partial_application/rfc_examples.inc
@@ -0,0 +1,76 @@
+ [$pfa, $closure]) {
+ echo "# ", $test, ": ";
+ $pfaReflector = new ReflectionFunction($pfa);
+ $closureReflector = new ReflectionFunction($closure);
+
+ try {
+ if (count($pfaReflector->getParameters()) !== count($closureReflector->getParameters())) {
+ throw new Exception(sprintf(
+ "Arity does not match: expected %d, got %d",
+ count($closureReflector->getParameters()),
+ count($pfaReflector->getParameters()),
+ ));
+ }
+
+ $it = new MultipleIterator();
+ $it->attachIterator(new ArrayIterator($pfaReflector->getParameters()));
+ $it->attachIterator(new ArrayIterator($closureReflector->getParameters()));
+ foreach ($it as $i => [$pfaParam, $closureParam]) {
+ [$i] = $i;
+ if ($pfaParam->getName() !== $closureParam->getName()) {
+ throw new Exception(sprintf("Name of param %d does not match: %s vs %s",
+ $i,
+ $pfaParam->getName(),
+ $closureParam->getName(),
+ ));
+ }
+ if ((string)$pfaParam->getType() !== (string)$closureParam->getType()) {
+ throw new Exception(sprintf("Type of param %d does not match: %s vs %s",
+ $i,
+ $pfaParam->getType(),
+ $closureParam->getType(),
+ ));
+ }
+ if ($pfaParam->isOptional() !== $closureParam->isOptional()) {
+ throw new Exception(sprintf("Optionalness of param %d does not match: %d vs %d",
+ $i,
+ $pfaParam->isOptional(),
+ $closureParam->isOptional(),
+ ));
+ }
+ }
+
+ $args = [];
+ foreach ($pfaReflector->getParameters() as $i => $p) {
+ $args[] = match ((string) $p->getType()) {
+ 'int' => 100 + $i,
+ 'float' => 100.5 + $i,
+ '?float' => 100.5 + $i,
+ 'string' => (string) (100 + $i),
+ 'Point' => new Point,
+ 'mixed' => "mixed($i)",
+ '' => "mixed($i)",
+ };
+ }
+
+ if ($pfaReflector->getClosureThis() !== $closureReflector->getClosureThis()) {
+ throw new Exception("\$this differs");
+ }
+
+ if ($pfa(...$args) !== $closure(...$args)) {
+ throw new Exception("PFA is not equivalent to closure");
+ }
+ } catch (Exception $e) {
+ echo $e->getMessage(), "\n";
+ echo $pfaReflector;
+ echo $closureReflector;
+ return;
+ }
+
+ echo "Ok\n";
+ }
+}
diff --git a/Zend/tests/partial_application/rfc_examples_const_expr.phpt b/Zend/tests/partial_application/rfc_examples_const_expr.phpt
new file mode 100644
index 000000000000..e2fc57440256
--- /dev/null
+++ b/Zend/tests/partial_application/rfc_examples_const_expr.phpt
@@ -0,0 +1,25 @@
+--TEST--
+PFA RFC examples: "Constant expressions" section
+--XFAIL--
+PFA in constant expressions not implemented yet
+--FILE--
+
+==DONE==
+--EXPECTF--
+==DONE==
diff --git a/Zend/tests/partial_application/rfc_examples_debug.phpt b/Zend/tests/partial_application/rfc_examples_debug.phpt
new file mode 100644
index 000000000000..9c5501090d4e
--- /dev/null
+++ b/Zend/tests/partial_application/rfc_examples_debug.phpt
@@ -0,0 +1,25 @@
+--TEST--
+PFA RFC examples: "Debug output" section
+--FILE--
+
+--EXPECTF--
+Fatal error: Uncaught Exception in %s:%d
+Stack trace:
+#0 %s(%d): g()
+#1 %s(%d): f(1, Object(SensitiveParameterValue), 3)
+#2 %s(%d): {closure:pfa:%s}(1, Object(SensitiveParameterValue))
+#3 {main}
+ thrown in %s on line %d
diff --git a/Zend/tests/partial_application/rfc_examples_errors.phpt b/Zend/tests/partial_application/rfc_examples_errors.phpt
new file mode 100644
index 000000000000..21818d7446e3
--- /dev/null
+++ b/Zend/tests/partial_application/rfc_examples_errors.phpt
@@ -0,0 +1,34 @@
+--TEST--
+PFA RFC examples: "Error examples" section
+--FILE--
+getMessage(), "\n";
+}
+
+try {
+ stuff(?, ?, ?, ?, ?, ?);
+} catch (Error $e) {
+ echo $e::class, ": ", $e->getMessage(), "\n";
+}
+
+try {
+ stuff(?, ?, 3.5, $point, i: 5);
+} catch (Error $e) {
+ echo $e::class, ": ", $e->getMessage(), "\n";
+}
+
+?>
+--EXPECT--
+ArgumentCountError: Partial application of stuff() expects at least 4 arguments, 1 given
+ArgumentCountError: Partial application of stuff() expects at most 5 arguments, 6 given
+Error: Named parameter $i overwrites previous placeholder
diff --git a/Zend/tests/partial_application/rfc_examples_eval_order.phpt b/Zend/tests/partial_application/rfc_examples_eval_order.phpt
new file mode 100644
index 000000000000..2fd6c9422e92
--- /dev/null
+++ b/Zend/tests/partial_application/rfc_examples_eval_order.phpt
@@ -0,0 +1,30 @@
+--TEST--
+PFA RFC examples: "Evaluation order" section
+--FILE--
+ speak($who, getArg());
+print "Arnaud\n";
+$arrow('Larry');
+
+$partial = speak(?, getArg());
+print "Arnaud\n";
+$partial('Larry');
+
+?>
+--EXPECT--
+Arnaud
+getArg
+Larry: hi
+getArg
+Arnaud
+Larry: hi
diff --git a/Zend/tests/partial_application/rfc_examples_extra_args.phpt b/Zend/tests/partial_application/rfc_examples_extra_args.phpt
new file mode 100644
index 000000000000..f6a24df8cc71
--- /dev/null
+++ b/Zend/tests/partial_application/rfc_examples_extra_args.phpt
@@ -0,0 +1,54 @@
+--TEST--
+PFA RFC examples: "Variadics, func_get_args(), and extraneous arguments" section
+--FILE--
+ [
+ foo(1, ?),
+ static function (int $j) { return foo(1, $j); },
+ ],
+ 'If a PFA call has a ... placeholder, then any extraneous arguments will be passed through to the underlying function' => [
+ foo(1, ?, ...),
+ static function (int $j) { return foo(1, $j, ...array_slice(func_get_args(), 1)); },
+ ],
+ 'If a PFA call has a ... placeholder and the underlying function is variadic, then the trailing arguments will be forwarded directly but will get “collected” by the variadic parameter as normal' => [
+ foo2(1, ?, ...),
+ static function (int $j, ...$extra) { return foo2(1, $j, ...$extra); },
+ ],
+];
+
+check_equivalence($tests);
+
+echo "# The extra parameter here will be passed to the closure object, which will simply ignore it:\n";
+var_dump(foo(1, ?)(4, 'ignore me'));
+
+echo "# The extra parameter here will be passed to the closure object, which will forward it directly to the underlying function. It will be accessible only via ''func_get_args()'' et al:\n";
+var_dump(foo(1, ?, ...)(4, 'ignore me'));
+
+echo "# The extra parameter here will be passed to the closure object, which will forward it directly to the underlying function. It will show up as part of the \$extra array:\n";
+var_dump(foo2(1, ?, ...)(4, 'ignore me'));
+
+?>
+==DONE==
+--EXPECT--
+# If a PFA call has no ... placeholder, then any extraneous arguments to the resulting closure will be ignored. That is consistent with how manually writing the equivalent closure would behave, and is the same regardless of whether the underlying function is variadic: Ok
+# If a PFA call has a ... placeholder, then any extraneous arguments will be passed through to the underlying function: Ok
+# If a PFA call has a ... placeholder and the underlying function is variadic, then the trailing arguments will be forwarded directly but will get “collected” by the variadic parameter as normal: Ok
+# The extra parameter here will be passed to the closure object, which will simply ignore it:
+int(2)
+# The extra parameter here will be passed to the closure object, which will forward it directly to the underlying function. It will be accessible only via ''func_get_args()'' et al:
+int(3)
+# The extra parameter here will be passed to the closure object, which will forward it directly to the underlying function. It will show up as part of the $extra array:
+int(3)
+==DONE==
diff --git a/Zend/tests/partial_application/rfc_examples_incompatible_functions.phpt b/Zend/tests/partial_application/rfc_examples_incompatible_functions.phpt
new file mode 100644
index 000000000000..dd99cb229ae8
--- /dev/null
+++ b/Zend/tests/partial_application/rfc_examples_incompatible_functions.phpt
@@ -0,0 +1,14 @@
+--TEST--
+PFA RFC examples: "Incompatible functions" section
+--FILE--
+getMessage(), "\n";
+}
+
+?>
+--EXPECT--
+Error: Cannot call func_get_arg() dynamically
diff --git a/Zend/tests/partial_application/rfc_examples_magic_methods.phpt b/Zend/tests/partial_application/rfc_examples_magic_methods.phpt
new file mode 100644
index 000000000000..7162a790c57c
--- /dev/null
+++ b/Zend/tests/partial_application/rfc_examples_magic_methods.phpt
@@ -0,0 +1,47 @@
+--TEST--
+PFA RFC examples: "Magic methods" section
+--FILE--
+ [
+ $f->method(?, ?),
+ (function ($f) {
+ return fn(mixed $arguments0, mixed $arguments1) => $f->method($arguments0, $arguments1);
+ })($f)->bindTo($f),
+ ],
+]);
+
+try {
+ $f->method(?, ?)(a: 1, b: 2);
+} catch (Error $e) {
+ echo $e::class, ": ", $e->getMessage(), "\n";
+}
+
+?>
+--EXPECT--
+# Test 1: Foo::method
+Array
+(
+ [0] => mixed(0)
+ [1] => mixed(1)
+)
+Foo::method
+Array
+(
+ [0] => mixed(0)
+ [1] => mixed(1)
+)
+Ok
+Error: Unknown named parameter $a
diff --git a/Zend/tests/partial_application/rfc_examples_overview.phpt b/Zend/tests/partial_application/rfc_examples_overview.phpt
new file mode 100644
index 000000000000..b6fc8c0586c2
--- /dev/null
+++ b/Zend/tests/partial_application/rfc_examples_overview.phpt
@@ -0,0 +1,44 @@
+--TEST--
+PFA RFC examples: "Overview" section
+--FILE--
+ [
+ foo(1, ?, 3, 4),
+ static fn(int $b): int => foo(1, $b, 3, 4),
+ ],
+ 'Test 2' => [
+ foo(1, ?, 3, ?),
+ static fn(int $b, int $d): int => foo(1, $b, 3, $d),
+ ],
+ 'Test 3' => [
+ foo(1, ...),
+ static fn(int $b, int $c, int $d): int => foo(1, $b, $c, $d),
+ ],
+ 'Test 4' => [
+ foo(1, 2, ...),
+ static fn(int $c, int $d): int => foo(1, 2, $c, $d),
+ ],
+ 'Test 5' => [
+ foo(1, ?, 3, ...),
+ static fn(int $b, int $d): int => foo(1, $b, 3, $d),
+ ],
+];
+
+check_equivalence($tests);
+
+?>
+--EXPECT--
+# Test 1: Ok
+# Test 2: Ok
+# Test 3: Ok
+# Test 4: Ok
+# Test 5: Ok
diff --git a/Zend/tests/partial_application/rfc_examples_scoping.phpt b/Zend/tests/partial_application/rfc_examples_scoping.phpt
new file mode 100644
index 000000000000..071b4a5a5a39
--- /dev/null
+++ b/Zend/tests/partial_application/rfc_examples_scoping.phpt
@@ -0,0 +1,113 @@
+--TEST--
+PFA RFC examples: "Scoping" section
+--FILE--
+ [
+ foo(?, ?),
+ static fn(int $i, int $j = 0): string => foo($i, $j),
+ ],
+ 'Static closure 2' => [
+ Foo::bar(?, ?),
+ static fn(int $i, int $j): string => Foo::bar($i, $j),
+ ],
+ 'Static closure 3' => [
+ foo(?, ?)(1, ?),
+ static fn(int $j = 0): string => foo(1, $j),
+ ],
+ 'Static closure 4' => [
+ foo(...)(?),
+ static fn(int $i): string => foo($i, 0),
+ ],
+];
+
+check_equivalence($tests);
+
+$c = new C();
+$f = $c->f(?);
+
+echo "# Cannot unbind \$this:\n";
+var_dump($f->bindTo(null, C::class)); // Warning: Cannot unbind $this of method, this will be an error in PHP 9 (returns null)
+
+echo "# Cannot rebind scope:\n";
+var_dump($f->bindTo($c, CSubClass::class)); // Warning: Cannot rebind scope of closure created from method, this will be an error in PHP 9 (returns null)
+
+echo "# Can rebind \$this with subclass:\n";
+var_dump($f->bindTo(new CSubClass, C::class)); // Allowed
+
+echo "# Cannot rebind \$this with unrelated class:\n";
+$f = $f->bindTo(new Unrelated, C::class); // Warning: Cannot bind method C::{closure:/path/to/test.php:11}() to object of class Unrelated, this will be an error in PHP 9 (returns null)
+
+echo "# self resolution:\n";
+$c = new CSubClass();
+var_dump($c->f(?)(1)); // string(1) "C"
+var_dump($c->g(?)(1)); // string(9) "CSubClass"
+var_dump($c->h(1)(1)); // string(1) "C"
+
+?>
+--EXPECTF--
+# Static closure 1: Ok
+# Static closure 2: Ok
+# Static closure 3: Ok
+# Static closure 4: Ok
+# Cannot unbind $this:
+
+Warning: Cannot unbind $this of method, this will be an error in PHP 9 in %s on line %d
+NULL
+# Cannot rebind scope:
+
+Warning: Cannot rebind scope of closure created from method, this will be an error in PHP 9 in %s on line %d
+NULL
+# Can rebind $this with subclass:
+object(Closure)#%d (5) {
+ ["name"]=>
+ string(%d) "{closure:pfa:%s}"
+ ["file"]=>
+ string(%d) "%s"
+ ["line"]=>
+ int(53)
+ ["this"]=>
+ object(CSubClass)#%d (0) {
+ }
+ ["parameter"]=>
+ array(1) {
+ ["$a"]=>
+ string(10) ""
+ }
+}
+# Cannot rebind $this with unrelated class:
+
+Warning: Cannot bind method C::{closure:pfa:%s}() to object of class Unrelated, this will be an error in PHP 9 in %s on line %d
+# self resolution:
+string(1) "C"
+string(9) "CSubClass"
+string(1) "C"
diff --git a/Zend/tests/partial_application/rfc_examples_semantics.phpt b/Zend/tests/partial_application/rfc_examples_semantics.phpt
new file mode 100644
index 000000000000..a3ea25c30d6d
--- /dev/null
+++ b/Zend/tests/partial_application/rfc_examples_semantics.phpt
@@ -0,0 +1,30 @@
+--TEST--
+PFA RFC examples: "Placeholder Semantics" section
+--FILE--
+ [
+ foo(?, ?, ?, ?),
+ static fn(int $a, int $b, string $c0, string $c1) => foo($a, $b, $c0, $c1),
+ ],
+ 'Test 2' => [
+ stuff(1, ?, p: ?, f: 3.14, ...),
+ static fn(string $s, Point $p, int $m = 0) => stuff(1, $s, 3.14, $p, $m),
+ ],
+];
+
+check_equivalence($tests);
+
+?>
+--EXPECT--
+# Test 1: Ok
+# Test 2: Ok
diff --git a/Zend/tests/partial_application/rfc_examples_semantics_examples.phpt b/Zend/tests/partial_application/rfc_examples_semantics_examples.phpt
new file mode 100644
index 000000000000..9ee52d278689
--- /dev/null
+++ b/Zend/tests/partial_application/rfc_examples_semantics_examples.phpt
@@ -0,0 +1,217 @@
+--TEST--
+PFA RFC examples: "Placeholder Semantics: Examples" section
+--FILE--
+ [
+ stuff(?, ?, ...),
+ static fn(int $i1, string $s2, float $f3, Point $p4, int $m5 = 0): array
+ => stuff($i1, $s2, $f3, $p4, $m5),
+ ],
+ 'The degenerate "first class callables" case. (Supported since 8.1)' => [
+ stuff(...),
+ static fn(int $i1, string $s2, float $f3, Point $p4, int $m5 = 0): array
+ => stuff($i1, $s2, $f3, $p4, $m5),
+ ],
+ 'Provide some values, require the rest to be provided later (1)' => [
+ stuff(1, 'hi', ?, ?, ?),
+ static fn(float $f3, Point $p4, int $m5 = 0): array => stuff(1, 'hi', $f3, $p4, $m5),
+ ],
+ 'Provide some values, require the rest to be provided later (2)' => [
+ stuff(1, 'hi', ...),
+ static fn(float $f3, Point $p4, int $m5 = 0): array => stuff(1, 'hi', $f3, $p4, $m5),
+ ],
+ 'Provide some values, but not just from the left (1)' => [
+ stuff(1, ?, 3.5, ?, ?),
+ static fn(string $s2, Point $p4, int $m5 = 0): array => stuff(1, $s2, 3.5, $p4, $m5),
+ ],
+ 'Provide some values, but not just from the left (2)' => [
+ stuff(1, ?, 3.5, ...),
+ static fn(string $s2, Point $p4, int $m5 = 0): array => stuff(1, $s2, 3.5, $p4, $m5),
+ ],
+ 'Provide just the last value' => [
+ stuff(?, ?, ?, ?, 5),
+ static fn(int $i1, string $s2, float $f3, Point $p4): array
+ => stuff($i1, $s2, $f3, $p4, 5),
+ ],
+ 'Not accounting for an optional argument means it will always get its default value' => [
+ stuff(?, ?, ?, ?),
+ static fn(int $i1, string $s2, float $f3, Point $p4): array
+ => stuff($i1, $s2, $f3, $p4),
+ ],
+ 'Named arguments can be pulled "out of order", and still work (1)' => [
+ stuff(?, ?, f3: 3.5, p4: $point),
+ static fn(int $i1, string $s2): array => stuff($i1, $s2, 3.5, $point),
+ ],
+ 'Named arguments can be pulled "out of order", and still work (2)' => [
+ stuff(?, ?, p4: $point, f3: 3.5),
+ static fn(int $i1, string $s2): array => stuff($i1, $s2, 3.5, $point),
+ ],
+
+ 'But named placeholders adopt the order listed' => [
+ stuff(s2: ?, i1: ?, p4: ?, f3: 3.5),
+ static fn(string $s2, int $i1, Point $p4): array => stuff($i1, $s2, 3.5, $p4),
+ ],
+ 'The ... "everything else" placeholder respects named arguments' => [
+ stuff(?, ?, f3: 3.5, p4: $point, ...),
+ static fn(int $i1, string $s2, int $m5 = 0): array => stuff($i1, $s2, 3.5, $point, $m5),
+ ],
+ 'Prefill all parameters, making a "delayed call" or "thunk"' => [
+ stuff(1, 'hi', 3.4, $point, 5, ...),
+ static fn(): array => stuff(1, 'hi', 3.4, $point, 5),
+ ],
+
+ // Variadics
+
+ 'FCC equivalent. The signature is unchanged' => [
+ things(...),
+ static fn(int $i1, ?float $f3 = null, Point ...$points): array => things(...[$i1, $f3, ...$points]),
+ ],
+ 'Provide some values, but allow the variadic to remain variadic' => [
+ things(1, 3.14, ...),
+ static fn(Point ...$points): array => things(1, 3.14, ...$points),
+ ],
+ 'In this version, the partial requires precisely four arguments, the last two of which will get received by things() in the variadic parameter. Note too that $f becomes required in this case' => [
+ things(?, ?, ?, ?),
+ static fn(int $i1, ?float $f3, Point $points0, Point $points1): array => things($i1, $f3, $points0, $points1),
+ ],
+
+ // Esoteric examples
+
+ 'Esoteric 1' => [
+ four(...),
+ static fn(int $a, int $b, int $c, int $d): string => four($a, $b, $c, $d),
+ ],
+ 'Esoteric 2' => [
+ four(1, 2, ...),
+ static fn(int $c, int $d): string => four(1, 2, $c, $d),
+ ],
+ 'Esoteric 3' => [
+ four(1, 2, 3, ?),
+ static fn(int $d): string => four(1, 2, 3, $d),
+ ],
+ 'Esoteric 4' => [
+ four(1, ?, ?, 4),
+ static fn(int $b, int $c): string => four(1, $b, $c, 4),
+ ],
+ 'Esoteric 5' => [
+ four(1, 2, 3, 4, ...),
+ static fn(): string => four(1, 2, 3, 4, ...array_slice(func_get_args(), 4)),
+ ],
+ 'Esoteric 6' => [
+ four(d: 4, a: 1, ...),
+ static fn(int $b, int $c): string => four(1, $b, $c, 4, ...array_slice(func_get_args(), 4)),
+ ],
+ 'Esoteric 7' => [
+ four(c: ?, d: 4, b: ?, a: 1),
+ static fn(int $c, int $b): string => four(1, $b, $c, 4, ...array_slice(func_get_args(), 4)),
+ ],
+
+ // Other callable styles
+
+ 'This is allowed. Note the method is static, thus the partial closure is static' => [
+ E::make(1, ?),
+ static fn(int $y): E => E::make(1, $y),
+ ],
+ 'Note the method is non-static, so the partial closure is non-static' => (function () {
+ $eMaker = E::make(1, ?);
+ $e = $eMaker(2);
+ return [
+ $e->foo(?, ?, 3),
+ (function ($e) {
+ return fn(int $a, int $b): array => $e->foo($a, $b, 3);
+ })($e)->bindTo($e),
+ ];
+ })(),
+ '$c can then be further refined' => (function () {
+ $eMaker = E::make(1, ?);
+ $e = $eMaker(2);
+ $c = $e->foo(?, ?, 3);
+ return [
+ $c(1, ?),
+ (function ($e) {
+ return fn(int $b): array => $e->foo(1, $b, 3);
+ })($e)->bindTo($e),
+ ];
+ })(),
+ 'RunMe' => (function () {
+ $r = new RunMe();
+ return [
+ $r(?, 3),
+ (function ($r) {
+ return fn(int $a): string => $r($a, 3);
+ })($r)->bindTo($r),
+ ];
+ })(),
+];
+
+check_equivalence($tests);
+
+?>
+--EXPECT--
+# Manually specify the first two values, and pull the rest "as is": Ok
+# The degenerate "first class callables" case. (Supported since 8.1): Ok
+# Provide some values, require the rest to be provided later (1): Ok
+# Provide some values, require the rest to be provided later (2): Ok
+# Provide some values, but not just from the left (1): Ok
+# Provide some values, but not just from the left (2): Ok
+# Provide just the last value: Ok
+# Not accounting for an optional argument means it will always get its default value: Ok
+# Named arguments can be pulled "out of order", and still work (1): Ok
+# Named arguments can be pulled "out of order", and still work (2): Ok
+# But named placeholders adopt the order listed: Ok
+# The ... "everything else" placeholder respects named arguments: Ok
+# Prefill all parameters, making a "delayed call" or "thunk": Ok
+# FCC equivalent. The signature is unchanged: Ok
+# Provide some values, but allow the variadic to remain variadic: Ok
+# In this version, the partial requires precisely four arguments, the last two of which will get received by things() in the variadic parameter. Note too that $f becomes required in this case: Ok
+# Esoteric 1: Ok
+# Esoteric 2: Ok
+# Esoteric 3: Ok
+# Esoteric 4: Ok
+# Esoteric 5: Ok
+# Esoteric 6: Ok
+# Esoteric 7: Ok
+# This is allowed. Note the method is static, thus the partial closure is static: Ok
+# Note the method is non-static, so the partial closure is non-static: Ok
+# $c can then be further refined: Ok
+# RunMe: Ok
diff --git a/Zend/tests/partial_application/static_method_001.phpt b/Zend/tests/partial_application/static_method_001.phpt
new file mode 100644
index 000000000000..ce4151441c33
--- /dev/null
+++ b/Zend/tests/partial_application/static_method_001.phpt
@@ -0,0 +1,18 @@
+--TEST--
+PFA supports static methods
+--FILE--
+
+--EXPECTF--
+Foo::method
diff --git a/Zend/tests/partial_application/static_pfa_001.phpt b/Zend/tests/partial_application/static_pfa_001.phpt
new file mode 100644
index 000000000000..bc0f65b1ffd8
--- /dev/null
+++ b/Zend/tests/partial_application/static_pfa_001.phpt
@@ -0,0 +1,45 @@
+--TEST--
+PFA of static method is static
+--FILE--
+f(?);
+echo new ReflectionFunction($f), "\n";
+$f(1);
+
+// Warns
+var_dump($f->bindTo(new C));
+
+?>
+--EXPECTF--
+Closure [ static public method {closure:pfa:%s:9} ] {
+ @@ %s 9 - 9
+
+ - Parameters [1] {
+ Parameter #0 [ $a ]
+ }
+}
+
+int(1)
+Closure [ static public method {closure:pfa:%s:13} ] {
+ @@ %s 13 - 13
+
+ - Parameters [1] {
+ Parameter #0 [ $a ]
+ }
+}
+
+int(1)
+
+Warning: Cannot bind an instance to a static closure, this will be an error in PHP 9 in %s on line %d
+NULL
diff --git a/Zend/tests/partial_application/static_pfa_002.phpt b/Zend/tests/partial_application/static_pfa_002.phpt
new file mode 100644
index 000000000000..5222109958b8
--- /dev/null
+++ b/Zend/tests/partial_application/static_pfa_002.phpt
@@ -0,0 +1,35 @@
+--TEST--
+PFA of instance method is not static
+--FILE--
+f(?);
+echo new ReflectionFunction($f), "\n";
+$f($c);
+
+$c2 = new C();
+$f->bindTo($c2)($c2);
+
+?>
+--EXPECTF--
+Closure [ public method {closure:pfa:%s:10} ] {
+ @@ %s 10 - 10
+
+ - Parameters [1] {
+ Parameter #0 [ $a ]
+ }
+}
+
+object(C)#%d (0) {
+}
+bool(true)
+object(C)#%d (0) {
+}
+bool(true)
diff --git a/Zend/tests/partial_application/static_pfa_003.phpt b/Zend/tests/partial_application/static_pfa_003.phpt
new file mode 100644
index 000000000000..e7b3c187e187
--- /dev/null
+++ b/Zend/tests/partial_application/static_pfa_003.phpt
@@ -0,0 +1,30 @@
+--TEST--
+PFA of standalone function is static
+--FILE--
+bindTo(new class {}));
+
+?>
+--EXPECTF--
+Closure [ static function {closure:pfa:%s:7} ] {
+ @@ %s 7 - 7
+
+ - Parameters [1] {
+ Parameter #0 [ $a ]
+ }
+}
+
+int(1)
+
+Warning: Cannot bind an instance to a static closure, this will be an error in PHP 9 in %s on line %d
+NULL
diff --git a/Zend/tests/partial_application/static_pfa_004.phpt b/Zend/tests/partial_application/static_pfa_004.phpt
new file mode 100644
index 000000000000..9b842c91c4cd
--- /dev/null
+++ b/Zend/tests/partial_application/static_pfa_004.phpt
@@ -0,0 +1,39 @@
+--TEST--
+PFA of non-static closure is not static
+--FILE--
+bindTo($c2)($c2);
+
+?>
+--EXPECTF--
+Closure [ function {closure:pfa:%s:11} ] {
+ @@ %s 11 - 11
+
+ - Bound Variables [1] {
+ Variable #0 [ $fn ]
+ }
+
+ - Parameters [1] {
+ Parameter #0 [ $a ]
+ }
+}
+
+NULL
+bool(false)
+object(class@anonymous)#3 (0) {
+}
+bool(true)
diff --git a/Zend/tests/partial_application/static_pfa_005.phpt b/Zend/tests/partial_application/static_pfa_005.phpt
new file mode 100644
index 000000000000..2783485b2f49
--- /dev/null
+++ b/Zend/tests/partial_application/static_pfa_005.phpt
@@ -0,0 +1,34 @@
+--TEST--
+PFA of static closure is static
+--FILE--
+bindTo(new class {}));
+
+?>
+--EXPECTF--
+Closure [ static function {closure:pfa:%s:7} ] {
+ @@ %s 7 - 7
+
+ - Bound Variables [1] {
+ Variable #0 [ $fn ]
+ }
+
+ - Parameters [1] {
+ Parameter #0 [ $a ]
+ }
+}
+
+int(1)
+
+Warning: Cannot bind an instance to a static closure, this will be an error in PHP 9 in %s on line %d
+NULL
diff --git a/Zend/tests/partial_application/static_polymorphism.phpt b/Zend/tests/partial_application/static_polymorphism.phpt
new file mode 100644
index 000000000000..5f121c65c0e8
--- /dev/null
+++ b/Zend/tests/partial_application/static_polymorphism.phpt
@@ -0,0 +1,43 @@
+--TEST--
+PFA: static polymorphism
+--FILE--
+
+--EXPECT--
+P::m
+string(1) "a"
+C::m
+array(0) {
+}
+P::m
+string(1) "a"
+C::m
+array(0) {
+}
diff --git a/Zend/tests/partial_application/static_vars_001.phpt b/Zend/tests/partial_application/static_vars_001.phpt
new file mode 100644
index 000000000000..610cddf37b54
--- /dev/null
+++ b/Zend/tests/partial_application/static_vars_001.phpt
@@ -0,0 +1,21 @@
+--TEST--
+PFA static variables are shared (001)
+--FILE--
+
+--EXPECT--
+int(1)
+int(2)
diff --git a/Zend/tests/partial_application/static_vars_002.phpt b/Zend/tests/partial_application/static_vars_002.phpt
new file mode 100644
index 000000000000..4e6cc82b720d
--- /dev/null
+++ b/Zend/tests/partial_application/static_vars_002.phpt
@@ -0,0 +1,22 @@
+--TEST--
+PFA static variables are shared (002)
+--FILE--
+
+--EXPECT--
+int(1)
+int(2)
diff --git a/Zend/tests/partial_application/static_vars_003.phpt b/Zend/tests/partial_application/static_vars_003.phpt
new file mode 100644
index 000000000000..04328bf717b8
--- /dev/null
+++ b/Zend/tests/partial_application/static_vars_003.phpt
@@ -0,0 +1,25 @@
+--TEST--
+PFA static variables are shared (003)
+--FILE--
+
+--EXPECT--
+int(1)
+int(2)
diff --git a/Zend/tests/partial_application/superfluous_args_are_forwarded.phpt b/Zend/tests/partial_application/superfluous_args_are_forwarded.phpt
new file mode 100644
index 000000000000..506092655217
--- /dev/null
+++ b/Zend/tests/partial_application/superfluous_args_are_forwarded.phpt
@@ -0,0 +1,44 @@
+--TEST--
+PFAs forwards superfluous args iff a variadic placeholder is specified
+--FILE--
+
+--EXPECT--
+array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+}
+array(1) {
+ [0]=>
+ int(1)
+}
+array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+}
diff --git a/Zend/tests/partial_application/this.phpt b/Zend/tests/partial_application/this.phpt
new file mode 100644
index 000000000000..bda6900bae39
--- /dev/null
+++ b/Zend/tests/partial_application/this.phpt
@@ -0,0 +1,20 @@
+--TEST--
+PFA $this
+--FILE--
+method(new stdClass, ...);
+
+$baz = $bar(new stdClass, ...);
+
+var_dump($foo === $baz());
+?>
+--EXPECT--
+bool(true)
diff --git a/Zend/tests/partial_application/variation_call_001.phpt b/Zend/tests/partial_application/variation_call_001.phpt
new file mode 100644
index 000000000000..b9c1c19ec9c6
--- /dev/null
+++ b/Zend/tests/partial_application/variation_call_001.phpt
@@ -0,0 +1,31 @@
+--TEST--
+PFA variation: call
+--FILE--
+method(?, new Param);
+
+$closure(1);
+
+$closure->call(/* newThis: */ new Foo(), 10);
+?>
+--EXPECT--
+Bar: 1, Param
+Foo: 10, Param
diff --git a/Zend/tests/partial_application/variation_closure_001.phpt b/Zend/tests/partial_application/variation_closure_001.phpt
new file mode 100644
index 000000000000..1d31f22c7f8a
--- /dev/null
+++ b/Zend/tests/partial_application/variation_closure_001.phpt
@@ -0,0 +1,40 @@
+--TEST--
+PFA variation: Closure
+--FILE--
+
+--EXPECTF--
+Closure [ function {closure:%s:%d} ] {
+ @@ %s 5 - 5
+
+ - Bound Variables [2] {
+ Variable #0 [ $fn ]
+ Variable #1 [ $a ]
+ }
+
+ - Parameters [1] {
+ Parameter #0 [ $b ]
+ }
+}
+Closure [ function {closure:pfa:%s:%d} ] {
+ @@ %s 10 - 10
+
+ - Bound Variables [2] {
+ Variable #0 [ $fn2 ]
+ Variable #1 [ $a ]
+ }
+
+ - Parameters [1] {
+ Parameter #0 [ $fn ]
+ }
+}
diff --git a/Zend/tests/partial_application/variation_closure_002.phpt b/Zend/tests/partial_application/variation_closure_002.phpt
new file mode 100644
index 000000000000..41abe0aaab0e
--- /dev/null
+++ b/Zend/tests/partial_application/variation_closure_002.phpt
@@ -0,0 +1,28 @@
+--TEST--
+PFA variation: Closure::__invoke()
+--FILE--
+__invoke(1, ?);
+
+echo (string) new ReflectionFunction($function);
+
+$function(10);
+?>
+--EXPECTF--
+Closure [ public method {closure:%s:%d} ] {
+ @@ %svariation_closure_002.php 6 - 6
+
+ - Bound Variables [1] {
+ Variable #0 [ $a ]
+ }
+
+ - Parameters [1] {
+ Parameter #0 [ $b ]
+ }
+}
+int(1)
+int(10)
diff --git a/Zend/tests/partial_application/variation_closure_003.phpt b/Zend/tests/partial_application/variation_closure_003.phpt
new file mode 100644
index 000000000000..da567e179853
--- /dev/null
+++ b/Zend/tests/partial_application/variation_closure_003.phpt
@@ -0,0 +1,46 @@
+--TEST--
+PFA variation: Closure::__invoke() with $this
+--FILE--
+bar();
+
+$function = $closure->__invoke(1, ?);
+
+echo (string) new ReflectionFunction($function);
+
+var_dump($function(10));
+?>
+--EXPECTF--
+Closure [ public method {closure:%s:%d} ] {
+ @@ %svariation_closure_003.php 14 - 14
+
+ - Bound Variables [1] {
+ Variable #0 [ $a ]
+ }
+
+ - Parameters [1] {
+ Parameter #0 [ $b ]
+ }
+}
+array(2) {
+ [0]=>
+ object(Foo)#1 (0) {
+ }
+ [1]=>
+ array(2) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(10)
+ }
+}
diff --git a/Zend/tests/partial_application/variation_debug_001.phpt b/Zend/tests/partial_application/variation_debug_001.phpt
new file mode 100644
index 000000000000..d2f6458634e9
--- /dev/null
+++ b/Zend/tests/partial_application/variation_debug_001.phpt
@@ -0,0 +1,40 @@
+--TEST--
+PFA variation: var_dump(), user function
+--FILE--
+
+--EXPECTF--
+object(Closure)#%d (5) {
+ ["name"]=>
+ string(%d) "{closure:%s}"
+ ["file"]=>
+ string(%d) "%svariation_debug_001.php"
+ ["line"]=>
+ int(6)
+ ["static"]=>
+ array(4) {
+ ["b"]=>
+ object(stdClass)#%d (0) {
+ }
+ ["c"]=>
+ int(20)
+ ["c0"]=>
+ object(stdClass)#%d (0) {
+ }
+ ["extra_named_params"]=>
+ array(1) {
+ ["four"]=>
+ int(4)
+ }
+ }
+ ["parameter"]=>
+ array(1) {
+ ["$a"]=>
+ string(10) ""
+ }
+}
diff --git a/Zend/tests/partial_application/variation_debug_002.phpt b/Zend/tests/partial_application/variation_debug_002.phpt
new file mode 100644
index 000000000000..9a1121ed7918
--- /dev/null
+++ b/Zend/tests/partial_application/variation_debug_002.phpt
@@ -0,0 +1,49 @@
+--TEST--
+PFA variation: var_dump(), internal function
+--FILE--
+
+--EXPECTF--
+object(Closure)#%d (5) {
+ ["name"]=>
+ string(%d) "{closure:%s}"
+ ["file"]=>
+ string(%d) "%svariation_debug_002.php"
+ ["line"]=>
+ int(2)
+ ["static"]=>
+ array(3) {
+ ["array"]=>
+ array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ }
+ ["arrays0"]=>
+ array(3) {
+ [0]=>
+ int(4)
+ [1]=>
+ int(5)
+ [2]=>
+ int(6)
+ }
+ ["extra_named_params"]=>
+ array(1) {
+ ["four"]=>
+ object(stdClass)#%d (0) {
+ }
+ }
+ }
+ ["parameter"]=>
+ array(2) {
+ ["$callback"]=>
+ string(10) ""
+ ["$arrays"]=>
+ string(10) ""
+ }
+}
diff --git a/Zend/tests/partial_application/variation_ex_001.phpt b/Zend/tests/partial_application/variation_ex_001.phpt
new file mode 100644
index 000000000000..0f36e90f616d
--- /dev/null
+++ b/Zend/tests/partial_application/variation_ex_001.phpt
@@ -0,0 +1,14 @@
+--TEST--
+PFA variation: UAF in cleanup unfinished calls
+--FILE--
+getMessage(), "\n";
+}
+?>
+--EXPECTF--
+ArgumentCountError: Partial application of {closure:%s:%d}() expects at most 0 arguments, 1 given
diff --git a/Zend/tests/partial_application/variation_gc_001.phpt b/Zend/tests/partial_application/variation_gc_001.phpt
new file mode 100644
index 000000000000..2db49cc74363
--- /dev/null
+++ b/Zend/tests/partial_application/variation_gc_001.phpt
@@ -0,0 +1,19 @@
+--TEST--
+PFA variation: GC (001)
+--FILE--
+method = self::__construct(new stdClass, ...);
+ }
+}
+
+$foo = new Foo(new stdClass);
+$foo->bar = $foo;
+
+echo "OK";
+?>
+--EXPECT--
+OK
diff --git a/Zend/tests/partial_application/variation_gc_002.phpt b/Zend/tests/partial_application/variation_gc_002.phpt
new file mode 100644
index 000000000000..31c721e8e681
--- /dev/null
+++ b/Zend/tests/partial_application/variation_gc_002.phpt
@@ -0,0 +1,11 @@
+--TEST--
+PFA variation: GC (002)
+--FILE--
+prop = var_dump($obj, ?);
+
+echo "OK";
+?>
+--EXPECT--
+OK
diff --git a/Zend/tests/partial_application/variation_gc_003.phpt b/Zend/tests/partial_application/variation_gc_003.phpt
new file mode 100644
index 000000000000..23cdaa1c666f
--- /dev/null
+++ b/Zend/tests/partial_application/variation_gc_003.phpt
@@ -0,0 +1,15 @@
+--TEST--
+PFA variation: GC (003)
+--FILE--
+prop = test(?, x: $obj);
+
+echo "OK";
+?>
+--EXPECT--
+OK
diff --git a/Zend/tests/partial_application/variation_invoke_001.phpt b/Zend/tests/partial_application/variation_invoke_001.phpt
new file mode 100644
index 000000000000..9285c08da19b
--- /dev/null
+++ b/Zend/tests/partial_application/variation_invoke_001.phpt
@@ -0,0 +1,21 @@
+--TEST--
+PFA variation: __invoke()
+--FILE--
+__invoke(32));
+
+try {
+ $foo->nothing();
+} catch (Error $ex) {
+ echo $ex::class, ": ", $ex->getMessage(), "\n";
+}
+?>
+--EXPECT--
+int(42)
+Error: Call to undefined method Closure::nothing()
diff --git a/Zend/tests/partial_application/variation_nocall_001.phpt b/Zend/tests/partial_application/variation_nocall_001.phpt
new file mode 100644
index 000000000000..3fbb3ec8d8c3
--- /dev/null
+++ b/Zend/tests/partial_application/variation_nocall_001.phpt
@@ -0,0 +1,12 @@
+--TEST--
+PFA variation: no call args leak
+--FILE--
+
+--EXPECT--
+OK
diff --git a/Zend/tests/partial_application/variation_nocall_002.phpt b/Zend/tests/partial_application/variation_nocall_002.phpt
new file mode 100644
index 000000000000..cd4823f1bd05
--- /dev/null
+++ b/Zend/tests/partial_application/variation_nocall_002.phpt
@@ -0,0 +1,30 @@
+--TEST--
+PFA variation: no call, order of destruction
+--FILE--
+id, "\n";
+ }
+}
+$foo = new Foo;
+$f = $foo->method(?);
+$g = $f(?);
+
+$map = new WeakMap();
+$map[$f] = new Dtor(1);
+$map[$g] = new Dtor(2);
+
+unset($f);
+unset($g);
+
+echo "OK";
+?>
+--EXPECT--
+Dtor::__destruct 2
+Dtor::__destruct 1
+OK
diff --git a/Zend/tests/partial_application/variation_parent_001.phpt b/Zend/tests/partial_application/variation_parent_001.phpt
new file mode 100644
index 000000000000..98095f45009a
--- /dev/null
+++ b/Zend/tests/partial_application/variation_parent_001.phpt
@@ -0,0 +1,76 @@
+--TEST--
+PFA variation: parent
+--FILE--
+method(10, ...);
+$baz = $bar(20, ...);
+
+var_dump($baz, $c = $baz(), $c() === $foo);
+?>
+--EXPECTF--
+object(Closure)#%d (6) {
+ ["name"]=>
+ string(%d) "{closure:%s}"
+ ["file"]=>
+ string(%d) "%svariation_parent_001.php"
+ ["line"]=>
+ int(12)
+ ["static"]=>
+ array(2) {
+ ["fn"]=>
+ object(Closure)#%d (6) {
+ ["name"]=>
+ string(%d) "{closure:%s:%d}"
+ ["file"]=>
+ string(%d) "%s"
+ ["line"]=>
+ int(11)
+ ["static"]=>
+ array(1) {
+ ["a"]=>
+ int(10)
+ }
+ ["this"]=>
+ object(Foo)#%d (0) {
+ }
+ ["parameter"]=>
+ array(2) {
+ ["$b"]=>
+ string(10) ""
+ ["$c"]=>
+ string(10) ""
+ }
+ }
+ ["b"]=>
+ int(20)
+ }
+ ["this"]=>
+ object(Foo)#%d (0) {
+ }
+ ["parameter"]=>
+ array(1) {
+ ["$c"]=>
+ string(10) ""
+ }
+}
+object(Closure)#%d (4) {
+ ["name"]=>
+ string(25) "{closure:Foo::method():4}"
+ ["file"]=>
+ string(%d) "%s"
+ ["line"]=>
+ int(4)
+ ["this"]=>
+ object(Foo)#%d (0) {
+ }
+}
+bool(true)
diff --git a/Zend/tests/partial_application/variation_scope_001.phpt b/Zend/tests/partial_application/variation_scope_001.phpt
new file mode 100644
index 000000000000..0dcea0921c43
--- /dev/null
+++ b/Zend/tests/partial_application/variation_scope_001.phpt
@@ -0,0 +1,18 @@
+--TEST--
+PFA variation: called scope
+--FILE--
+method(new stdClass, ...);
+
+$bar();
+?>
+--EXPECT--
+Foo::method
diff --git a/Zend/tests/partial_application/variation_strict_001.phpt b/Zend/tests/partial_application/variation_strict_001.phpt
new file mode 100644
index 000000000000..835f6e138055
--- /dev/null
+++ b/Zend/tests/partial_application/variation_strict_001.phpt
@@ -0,0 +1,20 @@
+--TEST--
+PFA variation: strict_types declared
+--FILE--
+getMessage());
+}
+?>
+--EXPECTF--
+TypeError: {closure:%s:%d}(): Argument #1 ($int) must be of type int, string given, called in %s on line %d
diff --git a/Zend/tests/partial_application/variation_variadics_001.phpt b/Zend/tests/partial_application/variation_variadics_001.phpt
new file mode 100644
index 000000000000..4710ca4d3b99
--- /dev/null
+++ b/Zend/tests/partial_application/variation_variadics_001.phpt
@@ -0,0 +1,31 @@
+--TEST--
+PFA variation: variadics, user function
+--FILE--
+
+--EXPECTF--
+Closure [ static function {closure:%s:%d} ] {
+ @@ %s 6 - 6
+
+ - Bound Variables [2] {
+ Variable #0 [ $a ]
+ Variable #1 [ $b0 ]
+ }
+
+ - Parameters [1] {
+ Parameter #0 [ ...$b ]
+ }
+}
+int(10)
+int(100)
+int(1000)
+int(10000)
diff --git a/Zend/tests/partial_application/variation_variadics_002.phpt b/Zend/tests/partial_application/variation_variadics_002.phpt
new file mode 100644
index 000000000000..4269dd0e66f0
--- /dev/null
+++ b/Zend/tests/partial_application/variation_variadics_002.phpt
@@ -0,0 +1,25 @@
+--TEST--
+PFA variation: variadics, internal function
+--FILE--
+
+--EXPECTF--
+Closure [ static function {closure:%s:%d} ] {
+ @@ %svariation_variadics_002.php 2 - 2
+
+ - Bound Variables [2] {
+ Variable #0 [ $format ]
+ Variable #1 [ $values0 ]
+ }
+
+ - Parameters [1] {
+ Parameter #0 [ mixed ...$values ]
+ }
+ - Return [ string ]
+}
+100 1000 10000
diff --git a/Zend/tests/partial_application/variation_variadics_004.phpt b/Zend/tests/partial_application/variation_variadics_004.phpt
new file mode 100644
index 000000000000..228404dc8272
--- /dev/null
+++ b/Zend/tests/partial_application/variation_variadics_004.phpt
@@ -0,0 +1,45 @@
+--TEST--
+PFA variation: variadics and optional args
+--FILE--
+
+--EXPECT--
+# Bound year, pass day:
+2006-01-02
+# Bound month, pass day:
+2005-12-02
+# Bound month, bound year, pass day:
+2016-12-02
+# Bound month, no args:
+2005-12-01
+# Bound month, bound year, no args:
+2016-12-01
diff --git a/Zend/tests/partial_application/variation_variadics_006.phpt b/Zend/tests/partial_application/variation_variadics_006.phpt
new file mode 100644
index 000000000000..cda62a2f3bfb
--- /dev/null
+++ b/Zend/tests/partial_application/variation_variadics_006.phpt
@@ -0,0 +1,17 @@
+--TEST--
+PFA variation: named may overwrite variadic placeholder
+--FILE--
+
+--EXPECTF--
+array(1) {
+ [0]=>
+ string(1) "a"
+}
diff --git a/Zend/tests/partial_application/variation_variadics_007.phpt b/Zend/tests/partial_application/variation_variadics_007.phpt
new file mode 100644
index 000000000000..9624e05b449b
--- /dev/null
+++ b/Zend/tests/partial_application/variation_variadics_007.phpt
@@ -0,0 +1,14 @@
+--TEST--
+PFA variation: extra through variadic
+--FILE--
+ $a + $b));
+?>
+--EXPECT--
+int(3)
diff --git a/Zend/tests/partial_application/variation_variadics_008.phpt b/Zend/tests/partial_application/variation_variadics_008.phpt
new file mode 100644
index 000000000000..4190bb759e68
--- /dev/null
+++ b/Zend/tests/partial_application/variation_variadics_008.phpt
@@ -0,0 +1,16 @@
+--TEST--
+PFA variation: variadics wrong signature checked
+--FILE--
+getMessage() . PHP_EOL;
+}
+?>
+--EXPECTF--
+Partial application of {closure:%s:%d}() expects at most 1 arguments, 2 given
diff --git a/Zend/zend.c b/Zend/zend.c
index 2a5988273bcd..f4236053af3d 100644
--- a/Zend/zend.c
+++ b/Zend/zend.c
@@ -2,15 +2,14 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans |
| Zeev Suraski |
@@ -78,7 +77,7 @@ ZEND_API bool zend_dtrace_enabled;
/* version information */
static char *zend_version_info;
static uint32_t zend_version_info_length;
-#define ZEND_CORE_VERSION_INFO "Zend Engine v" ZEND_VERSION ", Copyright (c) Zend Technologies\n"
+#define ZEND_CORE_VERSION_INFO "Zend Engine v" ZEND_VERSION ", Copyright © Zend by Perforce\n"
#define PRINT_ZVAL_INDENT 4
/* true multithread-shared globals */
diff --git a/Zend/zend.h b/Zend/zend.h
index ebb7d2391955..0d5303192b57 100644
--- a/Zend/zend.h
+++ b/Zend/zend.h
@@ -2,15 +2,14 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans |
| Zeev Suraski |
@@ -281,7 +280,9 @@ typedef size_t (*zend_write_func_t)(const char *str, size_t str_length);
EG(bailout) = &__bailout; \
if (SETJMP(__bailout)==0) {
#define zend_catch \
+ ZEND_ASSERT(EG(bailout) == &__bailout); \
} else { \
+ ZEND_ASSERT(EG(bailout) == &__bailout); \
EG(bailout) = __orig_bailout;
#define zend_end_try() \
} \
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index 211a5d14e6c3..2643f9e61367 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -2,15 +2,14 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans |
| Zeev Suraski |
@@ -126,7 +125,7 @@ ZEND_API const char *zend_get_type_by_const(int type) /* {{{ */
return "mixed";
case _IS_NUMBER:
return "int|float";
- EMPTY_SWITCH_DEFAULT_CASE()
+ default: ZEND_UNREACHABLE();
}
}
/* }}} */
@@ -262,7 +261,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_error(int error_code,
case ZPP_ERROR_FAILURE:
ZEND_ASSERT(EG(exception) && "Should have produced an error already");
break;
- EMPTY_SWITCH_DEFAULT_CASE()
+ default: ZEND_UNREACHABLE();
}
}
/* }}} */
@@ -375,7 +374,9 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_unexpected_extra_named_error(void)
);
}
-ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_error_variadic(zend_class_entry *error_ce, uint32_t arg_num, const char *format, va_list va) /* {{{ */
+ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_error_variadic_ex(
+ const zend_function *function, uint32_t arg_num,
+ zend_class_entry *error_ce, const char *format, va_list va)
{
zend_string *func_name;
const char *arg_name;
@@ -384,8 +385,8 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_error_variadic(zend_class_en
return;
}
- func_name = get_active_function_or_method_name();
- arg_name = get_active_function_arg_name(arg_num);
+ func_name = get_function_or_method_name(function);
+ arg_name = get_function_arg_name(function, arg_num);
zend_vspprintf(&message, 0, format, va);
zend_throw_error(error_ce, "%s(): Argument #%d%s%s%s %s",
@@ -395,8 +396,27 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_error_variadic(zend_class_en
efree(message);
zend_string_release(func_name);
}
+
+ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_error_variadic(zend_class_entry *error_ce, uint32_t arg_num, const char *format, va_list va) /* {{{ */
+{
+ ZEND_ASSERT(zend_is_executing());
+
+ const zend_function *function = zend_active_function();
+
+ zend_argument_error_variadic_ex(function, arg_num, error_ce, format, va);
+}
/* }}} */
+ZEND_API ZEND_COLD void zend_argument_error_ex(const zend_function *function,
+ uint32_t arg_num, zend_class_entry *error_ce, const char *format, ...)
+{
+ va_list va;
+
+ va_start(va, format);
+ zend_argument_error_variadic_ex(function, arg_num, error_ce, format, va);
+ va_end(va);
+}
+
ZEND_API ZEND_COLD void zend_argument_error(zend_class_entry *error_ce, uint32_t arg_num, const char *format, ...) /* {{{ */
{
va_list va;
@@ -407,6 +427,18 @@ ZEND_API ZEND_COLD void zend_argument_error(zend_class_entry *error_ce, uint32_t
}
/* }}} */
+ZEND_API ZEND_COLD void zend_argument_type_error_ex(
+ const zend_function *function, uint32_t arg_num,
+ const char *format, ...)
+{
+ va_list va;
+
+ va_start(va, format);
+ zend_argument_error_variadic_ex(function, arg_num,
+ zend_ce_type_error, format, va);
+ va_end(va);
+}
+
ZEND_API ZEND_COLD void zend_argument_type_error(uint32_t arg_num, const char *format, ...) /* {{{ */
{
va_list va;
@@ -2997,6 +3029,7 @@ ZEND_API void zend_convert_internal_arg_info(zend_arg_info *new_arg_info, const
new_arg_info->name = NULL;
new_arg_info->default_value = NULL;
}
+ new_arg_info->doc_comment = NULL;
new_arg_info->type = arg_info->type;
zend_convert_internal_arg_info_type(&new_arg_info->type, persistent);
}
@@ -3045,7 +3078,6 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
internal_function->prop_info = NULL;
internal_function->attributes = NULL;
internal_function->frameless_function_infos = ptr->frameless_function_infos;
- internal_function->fn_flags2 = 0;
if (EG(active)) { // at run-time: this ought to only happen if registered with dl() or somehow temporarily at runtime
ZEND_MAP_PTR_INIT(internal_function->run_time_cache, zend_arena_calloc(&CG(arena), 1, zend_internal_run_time_cache_reserved_size()));
} else {
@@ -3055,7 +3087,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
ZEND_MAP_PTR_INIT(internal_function->run_time_cache, NULL);
#endif
}
- if (ptr->flags) {
+ if (ptr->flags & UINT32_MAX) {
if (!(ptr->flags & ZEND_ACC_PPP_MASK)) {
if (ptr->flags != ZEND_ACC_DEPRECATED && scope) {
zend_error(error_type, "Invalid access level for %s::%s() - access must be exactly one of public, protected or private", ZSTR_VAL(scope->name), ptr->fname);
@@ -3067,6 +3099,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
} else {
internal_function->fn_flags = ZEND_ACC_PUBLIC;
}
+ internal_function->fn_flags2 = ptr->flags >> 32;
if (ptr->arg_info) {
zend_internal_function_info *info = (zend_internal_function_info*)ptr->arg_info;
@@ -3769,6 +3802,10 @@ static bool zend_is_callable_check_class(zend_string *name, zend_class_entry *sc
if (error) zend_spprintf(error, 0, "class \"%.*s\" not found", (int)name_len, ZSTR_VAL(name));
}
ZSTR_ALLOCA_FREE(lcname, use_heap);
+ /* User error handlers may throw from deprecations above; do not report callable as valid. */
+ if (UNEXPECTED(EG(exception))) {
+ return false;
+ }
return ret;
}
/* }}} */
@@ -4030,7 +4067,7 @@ static zend_always_inline bool zend_is_callable_check_func(const zval *callable,
}
/* }}} */
-ZEND_API zend_string *zend_get_callable_name_ex(zval *callable, const zend_object *object) /* {{{ */
+ZEND_API zend_string *zend_get_callable_name_ex(const zval *callable, const zend_object *object) /* {{{ */
{
try_again:
switch (Z_TYPE_P(callable)) {
@@ -4088,7 +4125,7 @@ ZEND_API zend_string *zend_get_callable_name_ex(zval *callable, const zend_objec
}
/* }}} */
-ZEND_API zend_string *zend_get_callable_name(zval *callable) /* {{{ */
+ZEND_API zend_string *zend_get_callable_name(const zval *callable) /* {{{ */
{
return zend_get_callable_name_ex(callable, NULL);
}
@@ -4205,7 +4242,7 @@ ZEND_API bool zend_is_callable_at_frame(
}
/* }}} */
-ZEND_API bool zend_is_callable_ex(zval *callable, zend_object *object, uint32_t check_flags, zend_string **callable_name, zend_fcall_info_cache *fcc, char **error) /* {{{ */
+ZEND_API bool zend_is_callable_ex(const zval *callable, zend_object *object, uint32_t check_flags, zend_string **callable_name, zend_fcall_info_cache *fcc, char **error) /* {{{ */
{
/* Determine callability at the first parent user frame. */
const zend_execute_data *frame = EG(current_execute_data);
@@ -4220,13 +4257,13 @@ ZEND_API bool zend_is_callable_ex(zval *callable, zend_object *object, uint32_t
return ret;
}
-ZEND_API bool zend_is_callable(zval *callable, uint32_t check_flags, zend_string **callable_name) /* {{{ */
+ZEND_API bool zend_is_callable(const zval *callable, uint32_t check_flags, zend_string **callable_name) /* {{{ */
{
return zend_is_callable_ex(callable, NULL, check_flags, callable_name, NULL, NULL);
}
/* }}} */
-ZEND_API zend_result zend_fcall_info_init(zval *callable, uint32_t check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string **callable_name, char **error) /* {{{ */
+ZEND_API zend_result zend_fcall_info_init(const zval *callable, uint32_t check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string **callable_name, char **error) /* {{{ */
{
if (!zend_is_callable_ex(callable, NULL, check_flags, callable_name, fcc, error)) {
return FAILURE;
diff --git a/Zend/zend_API.h b/Zend/zend_API.h
index 60acbd63044d..8de5ef771c0a 100644
--- a/Zend/zend_API.h
+++ b/Zend/zend_API.h
@@ -2,15 +2,14 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans |
| Zeev Suraski |
@@ -37,7 +36,7 @@ typedef struct _zend_function_entry {
zif_handler handler;
const struct _zend_internal_arg_info *arg_info;
uint32_t num_args;
- uint32_t flags;
+ uint64_t flags;
const zend_frameless_function_info *frameless_function_infos;
const char *doc_comment;
} zend_function_entry;
@@ -75,6 +74,8 @@ typedef struct _zend_fcall_info_cache {
#define ZEND_FUNCTION(name) ZEND_NAMED_FUNCTION(zif_##name)
#define ZEND_METHOD(classname, name) ZEND_NAMED_FUNCTION(zim_##classname##_##name)
+#define ZEND_FENTRY_FLAGS(flags, flags2) (((uint64_t)flags) | ((uint64_t)flags2 << 32))
+
#define ZEND_FENTRY(zend_name, name, arg_info, flags) { #zend_name, name, arg_info, (uint32_t) (sizeof(arg_info)/sizeof(struct _zend_internal_arg_info)-1), flags, NULL, NULL },
#define ZEND_RAW_FENTRY(zend_name, name, arg_info, flags, frameless_function_infos, doc_comment) { zend_name, name, arg_info, (uint32_t) (sizeof(arg_info)/sizeof(struct _zend_internal_arg_info)-1), flags, frameless_function_infos, doc_comment },
@@ -410,13 +411,13 @@ ZEND_API ZEND_COLD void zend_wrong_property_read(const zval *object, zval *prope
#define IS_CALLABLE_SUPPRESS_DEPRECATIONS (1<<1)
ZEND_API void zend_release_fcall_info_cache(zend_fcall_info_cache *fcc);
-ZEND_API zend_string *zend_get_callable_name_ex(zval *callable, const zend_object *object);
-ZEND_API zend_string *zend_get_callable_name(zval *callable);
+ZEND_API zend_string *zend_get_callable_name_ex(const zval *callable, const zend_object *object);
+ZEND_API zend_string *zend_get_callable_name(const zval *callable);
ZEND_API bool zend_is_callable_at_frame(
const zval *callable, zend_object *object, const zend_execute_data *frame,
uint32_t check_flags, zend_fcall_info_cache *fcc, char **error);
-ZEND_API bool zend_is_callable_ex(zval *callable, zend_object *object, uint32_t check_flags, zend_string **callable_name, zend_fcall_info_cache *fcc, char **error);
-ZEND_API bool zend_is_callable(zval *callable, uint32_t check_flags, zend_string **callable_name);
+ZEND_API bool zend_is_callable_ex(const zval *callable, zend_object *object, uint32_t check_flags, zend_string **callable_name, zend_fcall_info_cache *fcc, char **error);
+ZEND_API bool zend_is_callable(const zval *callable, uint32_t check_flags, zend_string **callable_name);
ZEND_API const char *zend_get_module_version(const char *module_name);
ZEND_API zend_result zend_get_module_started(const char *module_name);
@@ -701,7 +702,7 @@ ZEND_API zend_result _call_user_function_impl(zval *object, zval *function_name,
* fci->params = NULL;
* The callable_name argument may be NULL.
*/
-ZEND_API zend_result zend_fcall_info_init(zval *callable, uint32_t check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string **callable_name, char **error);
+ZEND_API zend_result zend_fcall_info_init(const zval *callable, uint32_t check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string **callable_name, char **error);
/** Clear arguments connected with zend_fcall_info *fci
* If free_mem is not zero then the params array gets free'd as well
@@ -895,6 +896,8 @@ static zend_always_inline zend_result zend_forbid_dynamic_call(void)
const zend_execute_data *ex = EG(current_execute_data);
ZEND_ASSERT(ex != NULL && ex->func != NULL);
+ ZEND_ASSERT(ex->func->common.fn_flags2 & ZEND_ACC2_FORBID_DYN_CALLS);
+
if (ZEND_CALL_INFO(ex) & ZEND_CALL_DYNAMIC) {
zend_string *function_or_method_name = get_active_function_or_method_name();
zend_throw_error(NULL, "Cannot call %.*s() dynamically",
@@ -1560,8 +1563,16 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(uint32_t num, ch
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_or_null_error(uint32_t num, char *error);
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_unexpected_extra_named_error(void);
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_error_variadic(zend_class_entry *error_ce, uint32_t arg_num, const char *format, va_list va);
+ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_error_variadic_ex(
+ const zend_function *function, uint32_t arg_num,
+ zend_class_entry *error_ce, const char *format, va_list va);
ZEND_API ZEND_COLD void zend_argument_error(zend_class_entry *error_ce, uint32_t arg_num, const char *format, ...);
+ZEND_API ZEND_COLD void zend_argument_error_ex(const zend_function *function,
+ uint32_t arg_num, zend_class_entry *error_ce, const char *format, ...);
ZEND_API ZEND_COLD void zend_argument_type_error(uint32_t arg_num, const char *format, ...);
+ZEND_API ZEND_COLD void zend_argument_type_error_ex(
+ const zend_function *function, uint32_t arg_num,
+ const char *format, ...);
ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *format, ...);
ZEND_API ZEND_COLD void zend_argument_must_not_be_empty_error(uint32_t arg_num);
ZEND_API ZEND_COLD void zend_class_redeclaration_error(int type, const zend_class_entry *old_ce);
@@ -2482,7 +2493,7 @@ static zend_always_inline bool zend_parse_arg_resource(zval *arg, zval **dest, b
return 1;
}
-static zend_always_inline bool zend_parse_arg_func(zval *arg, zend_fcall_info *dest_fci, zend_fcall_info_cache *dest_fcc, bool check_null, char **error, bool free_trampoline)
+static zend_always_inline bool zend_parse_arg_func(const zval *arg, zend_fcall_info *dest_fci, zend_fcall_info_cache *dest_fcc, bool check_null, char **error, bool free_trampoline)
{
if (check_null && UNEXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
dest_fci->size = 0;
diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c
index bca2190976c7..942a8b8e1309 100644
--- a/Zend/zend_alloc.c
+++ b/Zend/zend_alloc.c
@@ -2,15 +2,14 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans |
| Zeev Suraski |
diff --git a/Zend/zend_alloc.h b/Zend/zend_alloc.h
index 264e13848d1b..ff51c4fe8652 100644
--- a/Zend/zend_alloc.h
+++ b/Zend/zend_alloc.h
@@ -2,15 +2,14 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans |
| Zeev Suraski |
diff --git a/Zend/zend_alloc_sizes.h b/Zend/zend_alloc_sizes.h
index 502b982a5052..f806056ad9d3 100644
--- a/Zend/zend_alloc_sizes.h
+++ b/Zend/zend_alloc_sizes.h
@@ -2,15 +2,14 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
+----------------------------------------------------------------------+
diff --git a/Zend/zend_arena.h b/Zend/zend_arena.h
index 37cda28f29db..9b917a47e927 100644
--- a/Zend/zend_arena.h
+++ b/Zend/zend_arena.h
@@ -2,15 +2,14 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
+----------------------------------------------------------------------+
diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c
index e6270262e452..5b1ff675e1c0 100644
--- a/Zend/zend_ast.c
+++ b/Zend/zend_ast.c
@@ -2,15 +2,14 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Bob Weinand |
| Dmitry Stogov |
@@ -814,7 +813,7 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_inner(
case IS_OBJECT:
zend_cast_zval_to_object(result, &op1, IS_VAR);
break;
- EMPTY_SWITCH_DEFAULT_CASE();
+ default: ZEND_UNREACHABLE();
}
zval_ptr_dtor_nogc(&op1);
if (UNEXPECTED(EG(exception))) {
@@ -1240,7 +1239,7 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_inner(
break;
}
- EMPTY_SWITCH_DEFAULT_CASE()
+ default: ZEND_UNREACHABLE();
}
zend_create_fake_closure(result, fptr, fptr->common.scope, called_scope, NULL);
@@ -1460,6 +1459,16 @@ ZEND_API zend_ast_ref * ZEND_FASTCALL zend_ast_copy(zend_ast *ast)
return ref;
}
+ZEND_API zend_ast * ZEND_FASTCALL zend_ast_dup(zend_ast *ast)
+{
+ ZEND_ASSERT(ast != NULL);
+
+ zend_ast *buf = zend_ast_alloc(zend_ast_tree_size(ast));
+ zend_ast_tree_copy(ast, buf);
+
+ return buf;
+}
+
ZEND_API void ZEND_FASTCALL zend_ast_destroy(zend_ast *ast)
{
tail_call:
@@ -1961,7 +1970,7 @@ static ZEND_COLD void zend_ast_export_zval(smart_str *str, const zval *zv, int p
case IS_CONSTANT_AST:
zend_ast_export_ex(str, Z_ASTVAL_P(zv), priority, indent);
break;
- EMPTY_SWITCH_DEFAULT_CASE();
+ default: ZEND_UNREACHABLE();
}
}
@@ -2396,7 +2405,7 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
case T_PROPERTY_C: APPEND_STR("__PROPERTY__");
case T_NS_C: APPEND_STR("__NAMESPACE__");
case T_CLASS_C: APPEND_STR("__CLASS__");
- EMPTY_SWITCH_DEFAULT_CASE();
+ default: ZEND_UNREACHABLE();
}
break;
case ZEND_AST_TYPE:
@@ -2405,7 +2414,7 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
case IS_CALLABLE: APPEND_STR("callable");
case IS_STATIC: APPEND_STR("static");
case IS_MIXED: APPEND_STR("mixed");
- EMPTY_SWITCH_DEFAULT_CASE();
+ default: ZEND_UNREACHABLE();
}
break;
case ZEND_AST_PLACEHOLDER_ARG:
@@ -2439,7 +2448,7 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
case IS_STRING: PREFIX_OP("(string)", 240, 241);
case IS_ARRAY: PREFIX_OP("(array)", 240, 241);
case IS_OBJECT: PREFIX_OP("(object)", 240, 241);
- EMPTY_SWITCH_DEFAULT_CASE();
+ default: ZEND_UNREACHABLE();
}
break;
case ZEND_AST_CAST_VOID:
@@ -2473,14 +2482,14 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
case ZEND_REQUIRE_ONCE: FUNC_OP("require_once");
case ZEND_REQUIRE: FUNC_OP("require");
case ZEND_EVAL: FUNC_OP("eval");
- EMPTY_SWITCH_DEFAULT_CASE();
+ default: ZEND_UNREACHABLE();
}
break;
case ZEND_AST_UNARY_OP:
switch (ast->attr) {
case ZEND_BW_NOT: PREFIX_OP("~", 240, 241);
case ZEND_BOOL_NOT: PREFIX_OP("!", 240, 241);
- EMPTY_SWITCH_DEFAULT_CASE();
+ default: ZEND_UNREACHABLE();
}
break;
case ZEND_AST_PRE_INC:
@@ -2555,12 +2564,6 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
smart_str_appendc(str, ')');
break;
}
- case ZEND_AST_PARENT_PROPERTY_HOOK_CALL:
- smart_str_append(str, Z_STR_P(zend_ast_get_zval(ast->child[0])));
- smart_str_appendc(str, '(');
- zend_ast_export_ex(str, ast->child[1], 0, indent);
- smart_str_appendc(str, ')');
- break;
case ZEND_AST_CALLABLE_CONVERT: {
zend_ast_fcc *fcc_ast = (zend_ast_fcc*)ast;
ast = fcc_ast->args;
@@ -2581,7 +2584,7 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
case ZEND_FETCH_CLASS_PARENT:
smart_str_append(str, ZSTR_KNOWN(ZEND_STR_PARENT));
break;
- EMPTY_SWITCH_DEFAULT_CASE()
+ default: ZEND_UNREACHABLE();
}
} else {
zend_ast_export_ns_name(str, ast->child[0], 0, indent);
@@ -2604,7 +2607,7 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
case ZEND_BW_AND: BINARY_OP(" &= ", 90, 91, 90);
case ZEND_BW_XOR: BINARY_OP(" ^= ", 90, 91, 90);
case ZEND_POW: BINARY_OP(" **= ", 90, 91, 90);
- EMPTY_SWITCH_DEFAULT_CASE();
+ default: ZEND_UNREACHABLE();
}
break;
case ZEND_AST_ASSIGN_COALESCE: BINARY_OP(" \?\?= ", 90, 91, 90);
@@ -2630,7 +2633,7 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
case ZEND_POW: BINARY_OP(" ** ", 250, 251, 250);
case ZEND_BOOL_XOR: BINARY_OP(" xor ", 40, 40, 41);
case ZEND_SPACESHIP: BINARY_OP(" <=> ", 180, 181, 181);
- EMPTY_SWITCH_DEFAULT_CASE();
+ default: ZEND_UNREACHABLE();
}
break;
case ZEND_AST_GREATER: BINARY_OP(" > ", 180, 181, 181);
@@ -2809,7 +2812,7 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
smart_str_appends(str, " insteadof ");
zend_ast_export_ex(str, ast->child[1], 0, indent);
break;
- case ZEND_AST_METHOD_REFERENCE:
+ case ZEND_AST_TRAIT_METHOD_REFERENCE:
if (ast->child[0]) {
zend_ast_export_name(str, ast->child[0], 0, indent);
smart_str_appends(str, "::");
@@ -2982,7 +2985,7 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
zend_ast_export_indent(str, indent);
smart_str_appendc(str, '}');
break;
- EMPTY_SWITCH_DEFAULT_CASE();
+ default: ZEND_UNREACHABLE();
}
return;
@@ -3079,7 +3082,7 @@ zend_ast * ZEND_FASTCALL zend_ast_with_attributes(zend_ast *ast, zend_ast *attr)
* zend_compile_const_decl() checks the kind of the list elements. */
ast = zend_ast_list_add(ast, attr);
break;
- EMPTY_SWITCH_DEFAULT_CASE()
+ default: ZEND_UNREACHABLE();
}
return ast;
diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h
index a88efefd85b2..c029d7615e47 100644
--- a/Zend/zend_ast.h
+++ b/Zend/zend_ast.h
@@ -2,15 +2,14 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Bob Weinand |
| Dmitry Stogov |
@@ -144,7 +143,7 @@ enum _zend_ast_kind {
ZEND_AST_DECLARE,
ZEND_AST_USE_TRAIT,
ZEND_AST_TRAIT_PRECEDENCE,
- ZEND_AST_METHOD_REFERENCE,
+ ZEND_AST_TRAIT_METHOD_REFERENCE,
ZEND_AST_NAMESPACE,
ZEND_AST_USE_ELEM,
ZEND_AST_TRAIT_ALIAS,
@@ -153,7 +152,6 @@ enum _zend_ast_kind {
ZEND_AST_MATCH,
ZEND_AST_MATCH_ARM,
ZEND_AST_NAMED_ARG,
- ZEND_AST_PARENT_PROPERTY_HOOK_CALL,
ZEND_AST_PIPE,
/* 3 child nodes */
@@ -352,7 +350,10 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast
ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_ex(zval *result, zend_ast *ast, zend_class_entry *scope, bool *short_circuited_ptr, zend_ast_evaluate_ctx *ctx);
ZEND_API zend_string *zend_ast_export(const char *prefix, zend_ast *ast, const char *suffix);
+/* Copies 'ast' to the heap, returns a refcounted AST reference */
ZEND_API zend_ast_ref * ZEND_FASTCALL zend_ast_copy(zend_ast *ast);
+/* Duplicates 'ast' on the arena */
+ZEND_API zend_ast * ZEND_FASTCALL zend_ast_dup(zend_ast *ast);
ZEND_API void ZEND_FASTCALL zend_ast_destroy(zend_ast *ast);
ZEND_API void ZEND_FASTCALL zend_ast_ref_destroy(zend_ast_ref *ast);
diff --git a/Zend/zend_atomic.c b/Zend/zend_atomic.c
index 5f6a7793beea..98a39c583437 100644
--- a/Zend/zend_atomic.c
+++ b/Zend/zend_atomic.c
@@ -1,12 +1,12 @@
/*
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | Copyright © The PHP Group and Contributors. |
+ +----------------------------------------------------------------------+
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Levi Morrison |
+----------------------------------------------------------------------+
@@ -57,7 +57,7 @@ ZEND_API void zend_atomic_int_store(zend_atomic_int *obj, int desired) {
zend_atomic_int_store_ex(obj, desired);
}
-#if defined(ZEND_WIN32) || defined(HAVE_SYNC_ATOMICS)
+#if (defined(ZEND_WIN32) || defined(HAVE_SYNC_ATOMICS)) && !defined(HAVE_C11_ATOMICS)
/* On these platforms it is non-const due to underlying APIs. */
ZEND_API bool zend_atomic_bool_load(zend_atomic_bool *obj) {
return zend_atomic_bool_load_ex(obj);
diff --git a/Zend/zend_atomic.h b/Zend/zend_atomic.h
index 56422a721fdb..31558996c3c3 100644
--- a/Zend/zend_atomic.h
+++ b/Zend/zend_atomic.h
@@ -1,12 +1,12 @@
/*
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | Copyright © The PHP Group and Contributors. |
+ +----------------------------------------------------------------------+
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Levi Morrison |
+----------------------------------------------------------------------+
@@ -39,7 +39,7 @@
* and alignment purposes.
*/
-#if defined(ZEND_WIN32) || defined(HAVE_SYNC_ATOMICS)
+#if (defined(ZEND_WIN32) || defined(HAVE_SYNC_ATOMICS)) && !defined(HAVE_C11_ATOMICS)
typedef struct zend_atomic_bool_s {
volatile char value;
} zend_atomic_bool;
@@ -68,7 +68,7 @@ typedef struct zend_atomic_int_s {
BEGIN_EXTERN_C()
-#ifdef ZEND_WIN32
+#if defined(ZEND_WIN32) && !defined(HAVE_C11_ATOMICS)
#ifndef InterlockedExchange8
#define InterlockedExchange8 _InterlockedExchange8
@@ -123,7 +123,7 @@ static zend_always_inline bool zend_atomic_int_compare_exchange_ex(zend_atomic_i
}
}
-/* On this platform it is non-const due to Iterlocked API*/
+/* On this platform it is non-const due to Interlocked API */
static zend_always_inline bool zend_atomic_bool_load_ex(zend_atomic_bool *obj) {
/* Or'ing with false won't change the value. */
return InterlockedOr8(&obj->value, false);
@@ -376,7 +376,7 @@ ZEND_API bool zend_atomic_int_compare_exchange(zend_atomic_int *obj, int *expect
ZEND_API void zend_atomic_bool_store(zend_atomic_bool *obj, bool desired);
ZEND_API void zend_atomic_int_store(zend_atomic_int *obj, int desired);
-#if defined(ZEND_WIN32) || defined(HAVE_SYNC_ATOMICS)
+#if (defined(ZEND_WIN32) && !defined(HAVE_C11_ATOMICS)) || defined(HAVE_SYNC_ATOMICS)
/* On these platforms it is non-const due to underlying APIs. */
ZEND_API bool zend_atomic_bool_load(zend_atomic_bool *obj);
ZEND_API int zend_atomic_int_load(zend_atomic_int *obj);
diff --git a/Zend/zend_attributes.c b/Zend/zend_attributes.c
index cba95810ba49..71f0d788e921 100644
--- a/Zend/zend_attributes.c
+++ b/Zend/zend_attributes.c
@@ -2,15 +2,14 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Benjamin Eberlei |
| Martin Schröder |
diff --git a/Zend/zend_attributes.h b/Zend/zend_attributes.h
index f8b61ac9d166..c044ef073cc8 100644
--- a/Zend/zend_attributes.h
+++ b/Zend/zend_attributes.h
@@ -2,15 +2,14 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Benjamin Eberlei |
| Martin Schröder |
diff --git a/Zend/zend_autoload.c b/Zend/zend_autoload.c
index bc74efa1afda..2ca3d7eea022 100644
--- a/Zend/zend_autoload.c
+++ b/Zend/zend_autoload.c
@@ -2,15 +2,14 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Gina Peter Banyard |
+----------------------------------------------------------------------+
diff --git a/Zend/zend_autoload.h b/Zend/zend_autoload.h
index fde4a4a82e9a..84e6ab80b5af 100644
--- a/Zend/zend_autoload.h
+++ b/Zend/zend_autoload.h
@@ -2,15 +2,14 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Gina Peter Banyard |
+----------------------------------------------------------------------+
diff --git a/Zend/zend_bitset.h b/Zend/zend_bitset.h
index d990b6a2a871..877f2aaabc05 100644
--- a/Zend/zend_bitset.h
+++ b/Zend/zend_bitset.h
@@ -2,15 +2,13 @@
+----------------------------------------------------------------------+
| Zend OPcache JIT |
+----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
+ | Copyright © The PHP Group and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov |
+----------------------------------------------------------------------+
diff --git a/Zend/zend_build.h b/Zend/zend_build.h
index c604fb311a74..8ba7064042e3 100644
--- a/Zend/zend_build.h
+++ b/Zend/zend_build.h
@@ -2,15 +2,14 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Stanislav Malyshev |
+----------------------------------------------------------------------+
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
index 0a0f50362598..c19bf2779fbf 100644
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@ -2,21 +2,21 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans |
| Zeev Suraski |
+----------------------------------------------------------------------+
*/
+#include "php_version.h"
#include "zend.h"
#include "zend_API.h"
#include "zend_attributes.h"
diff --git a/Zend/zend_builtin_functions.h b/Zend/zend_builtin_functions.h
index 237b34b2927b..018d0cdb1c1d 100644
--- a/Zend/zend_builtin_functions.h
+++ b/Zend/zend_builtin_functions.h
@@ -2,15 +2,14 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Andi Gutmans |
| Zeev Suraski |
diff --git a/Zend/zend_builtin_functions.stub.php b/Zend/zend_builtin_functions.stub.php
index 9b2267b531eb..1d405587145d 100644
--- a/Zend/zend_builtin_functions.stub.php
+++ b/Zend/zend_builtin_functions.stub.php
@@ -18,11 +18,16 @@ function die(string|int $status = 0): never {}
/** @refcount 1 */
function zend_version(): string {}
+/** @forbid-dynamic-calls */
function func_num_args(): int {}
+/** @forbid-dynamic-calls */
function func_get_arg(int $position): mixed {}
-/** @return array */
+/**
+ * @return array
+ * @forbid-dynamic-calls
+ */
function func_get_args(): array {}
function strlen(string $string): int {}
@@ -156,6 +161,7 @@ function get_defined_functions(bool $exclude_disabled = true): array {}
/**
* @return array
* @refcount 1
+ * @forbid-dynamic-calls
*/
function get_defined_vars(): array {}
diff --git a/Zend/zend_builtin_functions_arginfo.h b/Zend/zend_builtin_functions_arginfo.h
index cb626ff430e6..b3af43fef340 100644
--- a/Zend/zend_builtin_functions_arginfo.h
+++ b/Zend/zend_builtin_functions_arginfo.h
@@ -1,5 +1,5 @@
/* This is a generated file, edit zend_builtin_functions.stub.php instead.
- * Stub hash: 9b49f527064695c812cd204d9efc63c13681d942 */
+ * Stub hash: 64c61862de86d9968930893bf21b516119724064 */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_clone, 0, 1, IS_OBJECT, 0)
ZEND_ARG_TYPE_INFO(0, object, IS_OBJECT, 0)
@@ -316,9 +316,21 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE(exit, arginfo_exit)
ZEND_RAW_FENTRY("die", zif_exit, arginfo_die, 0, NULL, NULL)
ZEND_FE(zend_version, arginfo_zend_version)
- ZEND_FE(func_num_args, arginfo_func_num_args)
- ZEND_FE(func_get_arg, arginfo_func_get_arg)
- ZEND_FE(func_get_args, arginfo_func_get_args)
+#if (PHP_VERSION_ID >= 80600)
+ ZEND_RAW_FENTRY("func_num_args", zif_func_num_args, arginfo_func_num_args, ZEND_FENTRY_FLAGS(0, ZEND_ACC2_FORBID_DYN_CALLS), NULL, NULL)
+#elif (PHP_VERSION_ID >= 80400)
+ ZEND_RAW_FENTRY("func_num_args", zif_func_num_args, arginfo_func_num_args, 0, NULL, NULL)
+#endif
+#if (PHP_VERSION_ID >= 80600)
+ ZEND_RAW_FENTRY("func_get_arg", zif_func_get_arg, arginfo_func_get_arg, ZEND_FENTRY_FLAGS(0, ZEND_ACC2_FORBID_DYN_CALLS), NULL, NULL)
+#elif (PHP_VERSION_ID >= 80400)
+ ZEND_RAW_FENTRY("func_get_arg", zif_func_get_arg, arginfo_func_get_arg, 0, NULL, NULL)
+#endif
+#if (PHP_VERSION_ID >= 80600)
+ ZEND_RAW_FENTRY("func_get_args", zif_func_get_args, arginfo_func_get_args, ZEND_FENTRY_FLAGS(0, ZEND_ACC2_FORBID_DYN_CALLS), NULL, NULL)
+#elif (PHP_VERSION_ID >= 80400)
+ ZEND_RAW_FENTRY("func_get_args", zif_func_get_args, arginfo_func_get_args, 0, NULL, NULL)
+#endif
ZEND_FE(strlen, arginfo_strlen)
ZEND_RAW_FENTRY("strcmp", zif_strcmp, arginfo_strcmp, ZEND_ACC_COMPILE_TIME_EVAL, NULL, NULL)
ZEND_RAW_FENTRY("strncmp", zif_strncmp, arginfo_strncmp, ZEND_ACC_COMPILE_TIME_EVAL, NULL, NULL)
@@ -358,7 +370,11 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE(get_declared_traits, arginfo_get_declared_traits)
ZEND_FE(get_declared_interfaces, arginfo_get_declared_interfaces)
ZEND_FE(get_defined_functions, arginfo_get_defined_functions)
- ZEND_FE(get_defined_vars, arginfo_get_defined_vars)
+#if (PHP_VERSION_ID >= 80600)
+ ZEND_RAW_FENTRY("get_defined_vars", zif_get_defined_vars, arginfo_get_defined_vars, ZEND_FENTRY_FLAGS(0, ZEND_ACC2_FORBID_DYN_CALLS), NULL, NULL)
+#elif (PHP_VERSION_ID >= 80400)
+ ZEND_RAW_FENTRY("get_defined_vars", zif_get_defined_vars, arginfo_get_defined_vars, 0, NULL, NULL)
+#endif
ZEND_FE(get_resource_type, arginfo_get_resource_type)
ZEND_FE(get_resource_id, arginfo_get_resource_id)
ZEND_FE(get_resources, arginfo_get_resources)
diff --git a/Zend/zend_call_stack.c b/Zend/zend_call_stack.c
index ed86ecc74a23..aa23c2e3e2fa 100644
--- a/Zend/zend_call_stack.c
+++ b/Zend/zend_call_stack.c
@@ -2,15 +2,14 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Arnaud Le Blanc |
+----------------------------------------------------------------------+
diff --git a/Zend/zend_call_stack.h b/Zend/zend_call_stack.h
index 58e91694f93f..c0b84334239d 100644
--- a/Zend/zend_call_stack.h
+++ b/Zend/zend_call_stack.h
@@ -2,15 +2,14 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Arnaud Le Blanc |
+----------------------------------------------------------------------+
diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c
index cca69985a0df..e1fd7c04f129 100644
--- a/Zend/zend_closures.c
+++ b/Zend/zend_closures.c
@@ -2,15 +2,14 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Christian Seiler |
| Dmitry Stogov |
@@ -28,6 +27,14 @@
#include "zend_globals.h"
#include "zend_closures_arginfo.h"
+/* Closure is a PFA */
+#define ZEND_PARTIAL OBJ_EXTRA_FLAG_PRIV_1
+/* Closure is a PFA of a Closure. Rebinding the PFA requires rebinding the inner Closure. */
+#define ZEND_PARTIAL_OF_CLOSURE OBJ_EXTRA_FLAG_PRIV_2
+
+#define ZEND_CLOSURE_FLAGS(closure) ((closure)->std.extra_flags & (ZEND_PARTIAL|ZEND_PARTIAL_OF_CLOSURE))
+#define ZEND_CLOSURE_IS_FAKE(closure) ((closure)->func.common.fn_flags & ZEND_ACC_FAKE_CLOSURE)
+
typedef struct _zend_closure {
zend_object std;
zend_function func;
@@ -41,6 +48,7 @@ ZEND_API zend_class_entry *zend_ce_closure;
static zend_object_handlers closure_handlers;
static zend_result zend_closure_get_closure(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr, bool check_only);
+static void zend_create_closure_ex(zval *res, zend_function *func, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr, bool is_fake, uint32_t flags);
ZEND_METHOD(Closure, __invoke) /* {{{ */
{
@@ -78,7 +86,9 @@ static bool zend_valid_closure_binding(
zend_closure *closure, zval *newthis, zend_class_entry *scope) /* {{{ */
{
zend_function *func = &closure->func;
- bool is_fake_closure = (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) != 0;
+ // TODO: rename variable
+ bool is_fake_closure = (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) != 0
+ || (closure->std.extra_flags & ZEND_PARTIAL);
if (newthis) {
if (func->common.fn_flags & ZEND_ACC_STATIC) {
zend_error(E_WARNING, "Cannot bind an instance to a static closure, this will be an error in PHP 9");
@@ -161,7 +171,9 @@ ZEND_METHOD(Closure, call)
if (closure->func.common.fn_flags & ZEND_ACC_GENERATOR) {
zval new_closure;
- zend_create_closure(&new_closure, &closure->func, newclass, closure->called_scope, newthis);
+ zend_create_closure_ex(&new_closure, &closure->func, newclass,
+ closure->called_scope, newthis,
+ ZEND_CLOSURE_IS_FAKE(closure), ZEND_CLOSURE_FLAGS(closure));
closure = (zend_closure *) Z_OBJ(new_closure);
fci_cache.function_handler = &closure->func;
@@ -177,6 +189,7 @@ ZEND_METHOD(Closure, call)
memset(&fake_closure->std, 0, sizeof(fake_closure->std));
fake_closure->std.gc.refcount = 1;
fake_closure->std.gc.u.type_info = GC_NULL;
+ fake_closure->std.extra_flags = ZEND_CLOSURE_FLAGS(closure);
ZVAL_UNDEF(&fake_closure->this_ptr);
fake_closure->called_scope = NULL;
my_function = &fake_closure->func;
@@ -223,7 +236,7 @@ ZEND_METHOD(Closure, call)
}
/* }}} */
-static void do_closure_bind(zval *return_value, zval *zclosure, zval *newthis, zend_object *scope_obj, zend_string *scope_str)
+static zend_result do_closure_bind(zval *return_value, zval *zclosure, zval *newthis, zend_object *scope_obj, zend_string *scope_str)
{
zend_class_entry *ce, *called_scope;
zend_closure *closure = (zend_closure *) Z_OBJ_P(zclosure);
@@ -235,14 +248,15 @@ static void do_closure_bind(zval *return_value, zval *zclosure, zval *newthis, z
ce = closure->func.common.scope;
} else if ((ce = zend_lookup_class(scope_str)) == NULL) {
zend_error(E_WARNING, "Class \"%s\" not found", ZSTR_VAL(scope_str));
- RETURN_NULL();
+ RETVAL_NULL();
+ return FAILURE;
}
} else {
ce = NULL;
}
if (!zend_valid_closure_binding(closure, newthis, ce)) {
- return;
+ return FAILURE;
}
if (newthis) {
@@ -251,7 +265,32 @@ static void do_closure_bind(zval *return_value, zval *zclosure, zval *newthis, z
called_scope = ce;
}
- zend_create_closure(return_value, &closure->func, ce, called_scope, newthis);
+ zend_create_closure_ex(return_value, &closure->func, ce, called_scope, newthis,
+ ZEND_CLOSURE_IS_FAKE(closure), ZEND_CLOSURE_FLAGS(closure));
+
+ if (ZEND_CLOSURE_FLAGS(closure) & ZEND_PARTIAL_OF_CLOSURE) {
+ /* Re-bind the inner closure */
+
+ closure = (zend_closure*)Z_OBJ_P(return_value);
+ HashTable *static_variables = ZEND_MAP_PTR_GET(closure->func.op_array.static_variables_ptr);
+ ZEND_ASSERT(static_variables->nNumOfElements > 0);
+ zval *inner = &static_variables->arData[0].val;
+ ZEND_ASSERT(Z_TYPE_P(inner) == IS_OBJECT && Z_OBJCE_P(inner) == zend_ce_closure);
+
+ zval new_inner;
+ if (do_closure_bind(&new_inner, inner, newthis, scope_obj, scope_str) != SUCCESS) {
+ ZEND_UNREACHABLE();
+ zval_ptr_dtor(return_value);
+ ZVAL_NULL(return_value);
+ return FAILURE;
+ }
+
+ zend_object *garbage = Z_OBJ_P(inner);
+ ZVAL_COPY_VALUE(inner, &new_inner);
+ zend_object_release(garbage);
+ }
+
+ return SUCCESS;
}
/* {{{ Create a closure from another one and bind to another object and scope */
@@ -588,8 +627,9 @@ static zend_object *zend_closure_clone(zend_object *zobject) /* {{{ */
zend_closure *closure = (zend_closure *)zobject;
zval result;
- zend_create_closure(&result, &closure->func,
- closure->func.common.scope, closure->called_scope, &closure->this_ptr);
+ zend_create_closure_ex(&result, &closure->func,
+ closure->func.common.scope, closure->called_scope, &closure->this_ptr,
+ ZEND_CLOSURE_IS_FAKE(closure), ZEND_CLOSURE_FLAGS(closure));
return Z_OBJ(result);
}
/* }}} */
@@ -750,13 +790,14 @@ static ZEND_NAMED_FUNCTION(zend_closure_internal_handler) /* {{{ */
{
zend_closure *closure = (zend_closure*)ZEND_CLOSURE_OBJECT(EX(func));
closure->orig_internal_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+ ZEND_ASSERT(!(closure->func.common.fn_flags2 & ZEND_ACC2_FORBID_DYN_CALLS) || EG(exception));
// Assign to EX(this) so that it is released after observer checks etc.
ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_RELEASE_THIS);
Z_OBJ(EX(This)) = &closure->std;
}
/* }}} */
-static void zend_create_closure_ex(zval *res, zend_function *func, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr, bool is_fake) /* {{{ */
+static void zend_create_closure_ex(zval *res, zend_function *func, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr, bool is_fake, uint32_t flags) /* {{{ */
{
zend_closure *closure;
void *ptr;
@@ -764,6 +805,7 @@ static void zend_create_closure_ex(zval *res, zend_function *func, zend_class_en
object_init_ex(res, zend_ce_closure);
closure = (zend_closure *)Z_OBJ_P(res);
+ closure->std.extra_flags = flags;
if ((scope == NULL) && this_ptr && (Z_TYPE_P(this_ptr) != IS_UNDEF)) {
/* use dummy scope if we're binding an object without specifying a scope */
@@ -861,14 +903,14 @@ static void zend_create_closure_ex(zval *res, zend_function *func, zend_class_en
ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr)
{
zend_create_closure_ex(res, func, scope, called_scope, this_ptr,
- /* is_fake */ (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) != 0);
+ /* is_fake */ (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) != 0, 0);
}
ZEND_API void zend_create_fake_closure(zval *res, zend_function *func, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr) /* {{{ */
{
zend_closure *closure;
- zend_create_closure_ex(res, func, scope, called_scope, this_ptr, /* is_fake */ true);
+ zend_create_closure_ex(res, func, scope, called_scope, this_ptr, /* is_fake */ true, 0);
closure = (zend_closure *)Z_OBJ_P(res);
closure->func.common.fn_flags |= ZEND_ACC_FAKE_CLOSURE;
@@ -878,6 +920,16 @@ ZEND_API void zend_create_fake_closure(zval *res, zend_function *func, zend_clas
}
/* }}} */
+ZEND_API void zend_create_partial_closure(zval *res, zend_function *func, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr, bool partial_of_closure)
+{
+ int flags = ZEND_PARTIAL;
+ if (partial_of_closure) {
+ flags |= ZEND_PARTIAL_OF_CLOSURE;
+ }
+ zend_create_closure_ex(res, func, scope, called_scope, this_ptr,
+ /* is_fake */ false, flags);
+}
+
void zend_closure_from_frame(zval *return_value, const zend_execute_data *call) { /* {{{ */
zval instance;
zend_internal_function trampoline;
diff --git a/Zend/zend_closures.h b/Zend/zend_closures.h
index 8bea4ffb051e..305d82e5015a 100644
--- a/Zend/zend_closures.h
+++ b/Zend/zend_closures.h
@@ -2,15 +2,14 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright © Zend Technologies Ltd., a subsidiary company of |
+ | Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
+ | This source file is subject to the Modified BSD License that is |
+ | bundled with this package in the file LICENSE, and is available |
+ | through the World Wide Web at . |
+ | |
+ | SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Christian Seiler |
| Dmitry Stogov