Skip to content

Commit 032adca

Browse files
Add php 8.4 compatibility (#1255)
1 parent d04bc88 commit 032adca

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+743
-149
lines changed

.ci/generate_package_lifecycle_test_matrix.sh

+6-1
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,13 @@ function generateAgentUpgradeRows () {
106106
local testingType=agent-upgrade
107107
local appHostKindShortName=all
108108
local testsGroup=smoke
109+
for phpVersion in 7.4 ; do
110+
for linuxPackageType in rpm ; do
111+
echo "${phpVersion},${linuxPackageType},${testingType},${appHostKindShortName},${testsGroup}"
112+
done
113+
done
109114
for phpVersion in 7.4 "$(latestSupportedPhpVersion)" ; do
110-
for linuxPackageType in deb rpm ; do
115+
for linuxPackageType in deb ; do
111116
echo "${phpVersion},${linuxPackageType},${testingType},${appHostKindShortName},${testsGroup}"
112117
done
113118
done

.ci/packer_cache.sh

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ php:8.0-fpm
1515
php:8.1-fpm
1616
php:8.2-fpm
1717
php:8.3-fpm
18+
php:8.4-fpm
1819
ruby:2.7.1-alpine3.12
1920
ubuntu:20.04
2021
"
@@ -26,7 +27,7 @@ if [ -x "$(command -v docker)" ]; then
2627

2728
# Make sure list of PHP versions supported by the Elastic APM PHP Agent is in sync.
2829
# See the comment in .ci/shared.sh
29-
for version in 7.2 7.3 7.4 8.0 8.1 8.2 8.3
30+
for version in 7.2 7.3 7.4 8.0 8.1 8.2 8.3 8.4
3031
do
3132
PHP_VERSION=${version} make -f .ci/Makefile prepare || true
3233
DOCKERFILE=Dockerfile.alpine PHP_VERSION=${version} make -f .ci/Makefile prepare || true

.ci/shared.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ set -e
1616
# *) docker-compose.yml in packaging/test
1717

1818
#
19-
export ELASTIC_APM_PHP_TESTS_SUPPORTED_PHP_VERSIONS=(7.2 7.3 7.4 8.0 8.1 8.2 8.3)
19+
export ELASTIC_APM_PHP_TESTS_SUPPORTED_PHP_VERSIONS=(7.2 7.3 7.4 8.0 8.1 8.2 8.3 8.4)
2020

2121
export ELASTIC_APM_PHP_TESTS_SUPPORTED_LINUX_NATIVE_PACKAGE_TYPES=(apk deb rpm)
2222
export ELASTIC_APM_PHP_TESTS_SUPPORTED_LINUX_PACKAGE_TYPES=("${ELASTIC_APM_PHP_TESTS_SUPPORTED_LINUX_NATIVE_PACKAGE_TYPES[@]}" tar)

.github/workflows/loop.yml

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ jobs:
2323
- "8.1"
2424
- "8.2"
2525
- "8.3"
26+
- "8.4"
2627
dockerfile:
2728
- "Dockerfile"
2829
- "Dockerfile.alpine"

.github/workflows/phpt.yml

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ jobs:
2828
- "8.1"
2929
- "8.2"
3030
- "8.3"
31+
- "8.4"
3132
steps:
3233
# - uses: actions/checkout@v4
3334
# - name: Fetch and extract latest release of apm-agent-php

.github/workflows/test.yml

+2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ jobs:
5858
- "8.1"
5959
- "8.2"
6060
- "8.3"
61+
- "8.4"
6162
data: ${{ fromJson(needs.setup-build-matrix.outputs.matrix-combinations).include }}
6263
env:
6364
PHP_VERSION: ${{ matrix.php-version }}
@@ -90,6 +91,7 @@ jobs:
9091
- "8.1"
9192
- "8.2"
9293
- "8.3"
94+
- "8.4"
9395
dockerfile:
9496
- "Dockerfile"
9597
- "Dockerfile.alpine"

agent/native/CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ include(elastic_conan_debugsymbols)
4343

4444
# Install project dependencies
4545

46-
set(_supported_php_versions 72 73 74 80 81 82 83)
46+
set(_supported_php_versions 72 73 74 80 81 82 83 84)
4747

4848
function(get_php_api_from_release php_version ret_val)
4949
block(SCOPE_FOR VARIABLES)
@@ -54,6 +54,7 @@ function(get_php_api_from_release php_version ret_val)
5454
set(_php_release_81 20210902)
5555
set(_php_release_82 20220829)
5656
set(_php_release_83 20230831)
57+
set(_php_release_84 20240924)
5758

5859
set(${ret_val} ${_php_release_${php_version}})
5960
return(PROPAGATE ${ret_val})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: "php-headers-84"
2+
version: "1.0"
3+
php_source_version: 8.4.1
4+
5+
sources:
6+
7.2.34:
7+
linux:
8+
- url: "https://www.php.net/distributions/php-7.2.34.tar.gz"
9+
contentsRoot: "php-7.2.34"
10+
7.3.33:
11+
linux:
12+
- url: "https://www.php.net/distributions/php-7.3.33.tar.gz"
13+
contentsRoot: "php-7.3.33"
14+
7.4.33:
15+
linux:
16+
- url: "https://www.php.net/distributions/php-7.4.33.tar.gz"
17+
contentsRoot: "php-7.4.33"
18+
8.0.28:
19+
linux:
20+
- url: "https://www.php.net/distributions/php-8.0.28.tar.gz"
21+
contentsRoot: "php-8.0.28"
22+
8.1.18:
23+
linux:
24+
- url: "https://www.php.net/distributions/php-8.1.18.tar.gz"
25+
contentsRoot: "php-8.1.18"
26+
8.2.5:
27+
linux:
28+
- url: "https://www.php.net/distributions/php-8.2.5.tar.gz"
29+
contentsRoot: "php-8.2.5"
30+
8.3.2:
31+
linux:
32+
- url: "https://www.php.net/distributions/php-8.3.2.tar.gz"
33+
contentsRoot: "php-8.3.2"
34+
8.4.1:
35+
linux:
36+
- url: "https://www.php.net/distributions/php-8.4.1.tar.gz"
37+
contentsRoot: "php-8.4.1"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import os
2+
import shutil
3+
4+
from conans import tools, ConanFile, AutoToolsBuildEnvironment
5+
6+
class PhpHeadersForPHP81Conan(ConanFile):
7+
description = "PHP headers package required to build Elastic APM agent without additional PHP dependencies"
8+
license = "The PHP License, version 3.01"
9+
homepage = "https://php.net/"
10+
url = "https://php.net/"
11+
author = "[email protected]"
12+
13+
settings = "os", "compiler", "build_type", "arch"
14+
platform = "linux"
15+
16+
def init(self):
17+
self.name = self.conan_data["name"]
18+
self.version = self.conan_data["version"] # version of the package
19+
self.php_version = self.conan_data["php_source_version"] # version of the PHP to build
20+
self.source_temp_dir = "php-src"
21+
22+
def requirements(self):
23+
self.requires("libxml2/2.9.9")
24+
self.requires("sqlite3/3.29.0")
25+
26+
def source(self):
27+
for source in self.conan_data["sources"][self.php_version][self.platform]:
28+
29+
if "contentsRoot" in source:
30+
# small hack - it can't contain custom fields, so we're removing it from source (got an unexpected keyword argument)
31+
contentRoot = source["contentsRoot"]
32+
del source["contentsRoot"]
33+
tools.get(**source)
34+
os.rename(contentRoot, self.source_temp_dir)
35+
else:
36+
self.output.error("Could not find 'contentsRoot' in conandata.yml")
37+
raise Exception("Could not find 'contentsRoot' in conandata.yml")
38+
39+
def build(self):
40+
with tools.chdir(os.path.join(self.source_folder, self.source_temp_dir)):
41+
buildEnv = AutoToolsBuildEnvironment(self)
42+
envVariables = buildEnv.vars
43+
envVariables['ac_cv_php_xml2_config_path'] = os.path.join(self.deps_cpp_info["libxml2"].rootpath, "bin/xml2-config")
44+
envVariables['LIBXML_LIBS'] = os.path.join(self.deps_cpp_info["libxml2"].rootpath, self.deps_cpp_info["libxml2"].libdirs[0])
45+
envVariables['LIBXML_CFLAGS'] = "-I{}".format(os.path.join(self.deps_cpp_info["libxml2"].rootpath, self.deps_cpp_info["libxml2"].includedirs[0]))
46+
envVariables['SQLITE_LIBS'] = os.path.join(self.deps_cpp_info["sqlite3"].rootpath, self.deps_cpp_info["sqlite3"].libdirs[0])
47+
envVariables['SQLITE_CFLAGS'] = "-I{}".format(os.path.join(self.deps_cpp_info["sqlite3"].rootpath, self.deps_cpp_info["sqlite3"].includedirs[0]))
48+
self.run("./buildconf --force")
49+
buildEnv.configure(args=[""], vars=envVariables, build=False, host=False)
50+
51+
def package(self):
52+
source = os.path.join(self.source_folder, self.source_temp_dir)
53+
self.copy("*.h", src=source, dst='include', keep_path=True)
54+
55+
def package_id(self):
56+
del self.info.settings.compiler.version

agent/native/ext/AST_debug.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,16 @@ String zendAstKindToString( zend_ast_kind kind )
224224
ELASTIC_APM_GEN_ENUM_TO_STRING_SWITCH_CASE( ZEND_AST_TYPE_INTERSECTION );
225225
#endif
226226

227-
228227
#if PHP_VERSION_ID >= ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 3, 0 ) /* if PHP version from 8.3.0 */
229228
ELASTIC_APM_GEN_ENUM_TO_STRING_SWITCH_CASE( ZEND_AST_MODIFIER_LIST );
230229
#endif
231230

231+
#if PHP_VERSION_ID >= ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 4, 0 ) /* if PHP version from 8.4.0 */
232+
ELASTIC_APM_GEN_ENUM_TO_STRING_SWITCH_CASE( ZEND_AST_PARENT_PROPERTY_HOOK_CALL );
233+
ELASTIC_APM_GEN_ENUM_TO_STRING_SWITCH_CASE( ZEND_AST_PROPERTY_HOOK );
234+
ELASTIC_APM_GEN_ENUM_TO_STRING_SWITCH_CASE( ZEND_AST_PROPERTY_HOOK_SHORT_BODY );
235+
#endif
236+
232237
default:
233238
return NULL;
234239
}

agent/native/ext/AST_instrumentation.cpp

+34-8
Original file line numberDiff line numberDiff line change
@@ -181,25 +181,47 @@ bool isZendAstListKind( zend_ast_kind kind )
181181
}
182182

183183
/**
184-
* zend_ast_create and zend_ast_create_ex allowed up to 4 child* parameters for version before PHP v8
185-
* and the limit was increased to 5 in PHP v8
184+
* Max number of children for AST nodes is
185+
* 4 for PHP before 8.0
186+
* 5 for PHP from 8.0 but before 8.4
187+
* 6 for PHP from 8.4
186188
*
187189
* @see ZEND_AST_SPEC_CALL_EX
190+
*
191+
* When adding support for a new PHP version:
192+
* - Make sure g_astNodeMaxChildCount is correct
193+
* - If g_astNodeMaxChildCount changed then update createAstEx()
194+
* - Make sure zendAstKindToString() in AST_debug.cpp includes all the enum cases from enum _zend_ast_kind in <php-src>/Zend/zend_ast.h
195+
* - Increment minor part of PHP version in static_assert below
188196
*/
189-
static size_t g_maxCreateAstChildCount =
197+
static_assert(
198+
PHP_VERSION_ID < ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 5, 0 ),
199+
"Make sure g_astNodeMaxChildCount is correct. See max number of children in enum _zend_ast_kind in <php-src>/Zend/zend_ast.h"
200+
);
201+
static constexpr size_t g_astNodeMaxChildCount =
202+
#if PHP_VERSION_ID < ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 0, 0 )
203+
4 // PHP before 8.0
204+
#elif PHP_VERSION_ID < ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 4, 0 )
205+
5 // PHP from 8.0 but before 8.4
206+
#else
207+
6 // PHP from 8.4
208+
#endif
209+
;
210+
static constexpr size_t g_zendKindWithLargestChildNodesCount =
190211
#if PHP_VERSION_ID < ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 0, 0 )
191-
4
212+
ZEND_AST_FOR // PHP before 8.0
192213
#else
193-
5
214+
ZEND_AST_PARAM // PHP from 8.0
194215
#endif
195216
;
217+
static_assert(g_zendKindWithLargestChildNodesCount == (g_astNodeMaxChildCount << ZEND_AST_NUM_CHILDREN_SHIFT));
196218

197219
zend_ast* createAstEx( zend_ast_kind kind, zend_ast_attr attr, ZendAstPtrArrayView children )
198220
{
199221
char txtOutStreamBuf[ELASTIC_APM_TEXT_OUTPUT_STREAM_ON_STACK_BUFFER_SIZE];
200222
TextOutputStream txtOutStream = ELASTIC_APM_TEXT_OUTPUT_STREAM_FROM_STATIC_BUFFER( txtOutStreamBuf );
201223

202-
ELASTIC_APM_ASSERT_LE_UINT64( children.count, g_maxCreateAstChildCount );
224+
ELASTIC_APM_ASSERT_LE_UINT64( children.count, g_astNodeMaxChildCount );
203225
ELASTIC_APM_ASSERT( ! isZendAstListKind( kind ), "kind: %s", streamZendAstKind( kind, &txtOutStream ) );
204226

205227
switch( children.count )
@@ -218,6 +240,10 @@ zend_ast* createAstEx( zend_ast_kind kind, zend_ast_attr attr, ZendAstPtrArrayVi
218240
case 5:
219241
return zend_ast_create_ex( kind, attr, children.values[ 0 ], children.values[ 1 ], children.values[ 2 ], children.values[ 3 ], children.values[ 4 ] );
220242
#endif
243+
#if PHP_VERSION_ID >= ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 4, 0 )
244+
case 6:
245+
return zend_ast_create_ex( kind, attr, children.values[ 0 ], children.values[ 1 ], children.values[ 2 ], children.values[ 3 ], children.values[ 4 ], children.values[ 5 ] );
246+
#endif
221247
default: // silence compiler warning
222248
return nullptr;
223249
}
@@ -227,9 +253,9 @@ ResultCode createAstExCheckChildrenCount( zend_ast_kind kind, zend_ast_attr attr
227253
{
228254
ResultCode resultCode;
229255

230-
if ( children.count > g_maxCreateAstChildCount )
256+
if ( children.count > g_astNodeMaxChildCount )
231257
{
232-
ELASTIC_APM_LOG_ERROR( "Number of children is larger than max; children.count: %u, g_maxCreateAstChildCount: %u", (unsigned)children.count, (unsigned)g_maxCreateAstChildCount );
258+
ELASTIC_APM_LOG_ERROR( "Number of children is larger than max; children.count: %u, g_astNodeMaxChildCount: %u", (unsigned)children.count, (unsigned)g_astNodeMaxChildCount );
233259
ELASTIC_APM_SET_RESULT_CODE_AND_GOTO_FAILURE_EX( resultFailure );
234260
}
235261

agent/native/ext/tests_util/tests_util.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
declare(strict_types=1);
2323

24-
error_reporting(E_ALL | E_STRICT);
24+
error_reporting(E_ALL);
2525

2626
function elasticApmOnAssertFailure(string $condDesc, string $expr, $actual, $expected)
2727
{

agent/native/loader/code/phpdetection.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,10 @@ bool isThreadSafe() {
5656

5757
std::tuple<std::string_view, int, bool> getZendModuleApiVersion(std::string_view zendVersion) {
5858
using namespace std::string_view_literals;
59-
constexpr size_t knownVersionsCount = 16;
59+
constexpr size_t knownVersionsCount = 17;
6060

6161
constexpr std::array<std::tuple<std::string_view, int, bool>, knownVersionsCount> knownPhpVersions {{
62+
{"4.4"sv, 20240924, true}, // PHP 8.4
6263
{"4.3"sv, 20230831, true}, // PHP 8.3
6364
{"4.2"sv, 20220829, true}, // PHP 8.2
6465
{"4.1"sv, 20210902, true}, // PHP 8.1
@@ -91,4 +92,4 @@ std::tuple<std::string_view, int, bool> getZendModuleApiVersion(std::string_view
9192

9293

9394

94-
}
95+
}

agent/php/ElasticApm/Impl/AutoInstrument/CurlHandleWrappedTrait.php

+1
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ public function setOpt(int $option, $value): bool
100100

101101
public function asInt(): int
102102
{
103+
/** @phpstan-ignore-next-line */
103104
return is_resource($this->curlHandle) ? intval($this->curlHandle) : spl_object_id($this->curlHandle);
104105
}
105106

agent/php/ElasticApm/Impl/AutoInstrument/TransactionForExtensionRequest.php

+1
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,7 @@ private function discoverStartTime(float $requestInitStartTime): float
572572
return $requestInitStartTime;
573573
}
574574

575+
/** @phpstan-ignore-next-line */
575576
$serverRequestTimeInSeconds = floatval($serverRequestTimeAsString);
576577
$serverRequestTimeInMicroseconds = $serverRequestTimeInSeconds * TimeUtil::NUMBER_OF_MICROSECONDS_IN_SECOND;
577578
if ($requestInitStartTime < $serverRequestTimeInMicroseconds) {

agent/php/ElasticApm/Impl/Config/IniRawSnapshotSource.php

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ private static function iniValueToString($iniValue): string
7979
return $iniValue ? 'true' : 'false';
8080
}
8181

82+
/** @phpstan-ignore-next-line */
8283
return strval($iniValue);
8384
}
8485
}

agent/php/ElasticApm/Impl/InferredSpansManager.php

+8-5
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,14 @@ private function onNewCurrentTransactionHasBegun(Transaction $transaction): void
205205
($assertProxy = Assert::ifEnabled())
206206
&& $assertProxy->that($this->onCurrentSpanChangedCallback === null)
207207
&& $assertProxy->withContext('$this->onCurrentSpanChangedCallback === null', ['this' => $this]);
208-
$this->currentTransaction->onCurrentSpanChanged->add(
209-
$this->onCurrentSpanChangedCallback = function (?Span $span): void {
210-
$this->onCurrentSpanChanged($span);
211-
}
212-
);
208+
209+
if ($this->currentTransaction !== null) {
210+
$this->currentTransaction->onCurrentSpanChanged->add(
211+
$this->onCurrentSpanChangedCallback = function (?Span $span): void {
212+
$this->onCurrentSpanChanged($span);
213+
}
214+
);
215+
}
213216

214217
$this->builder = new InferredSpansBuilder($this->tracer);
215218
$this->state = self::STATE_RUNNING;

agent/php/ElasticApm/Impl/Log/LoggableToJsonEncodable.php

+1
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ public static function convert($value, int $depth)
108108
return self::convertObject($value, $depth);
109109
}
110110

111+
/** @phpstan-ignore-next-line */
111112
return [LogConsts::TYPE_KEY => DbgUtil::getType($value), LogConsts::VALUE_AS_STRING_KEY => strval($value)];
112113
}
113114

agent/php/ElasticApm/Impl/Util/ArrayUtil.php

+10-9
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,18 @@ final class ArrayUtil
3333
use StaticClassTrait;
3434

3535
/**
36-
* @param string $key
37-
* @param array<mixed> $array
38-
* @param mixed $valueDst
36+
* @template TKey of array-key
37+
* @template TValue
3938
*
40-
* @return bool
39+
* @param TKey $key
40+
* @param array<TKey, TValue> $array
41+
* @param TValue &$valueDst
4142
*
42-
* @template T
43-
* @phpstan-param T[] $array
44-
* @phpstan-param T $valueDst
43+
* @param-out TValue $valueDst
44+
*
45+
* @return bool
4546
*/
46-
public static function getValueIfKeyExists(string $key, array $array, &$valueDst): bool
47+
public static function getValueIfKeyExists($key, array $array, /* out */ &$valueDst): bool
4748
{
4849
if (!array_key_exists($key, $array)) {
4950
return false;
@@ -54,7 +55,7 @@ public static function getValueIfKeyExists(string $key, array $array, &$valueDst
5455
}
5556

5657
/**
57-
* @template TKey of string|int
58+
* @template TKey of array-key
5859
* @template TValue
5960
*
6061
* @param TKey $key

0 commit comments

Comments
 (0)