agent/php/ElasticApm/Impl/BackendComm/SerializationUtil.php (90 lines of code) (raw):
<?php
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
declare(strict_types=1);
namespace Elastic\Apm\Impl\BackendComm;
use Elastic\Apm\Impl\OptionalSerializableDataInterface;
use Elastic\Apm\Impl\Util\ArrayUtil;
use Elastic\Apm\Impl\Util\BoolUtil;
use Elastic\Apm\Impl\Util\ExceptionUtil;
use Elastic\Apm\Impl\Util\JsonUtil;
use Elastic\Apm\Impl\Util\StaticClassTrait;
use Exception;
use JsonSerializable;
use stdClass;
/**
* Code in this file is part of implementation internals and thus it is not covered by the backward compatibility.
*
* @internal
*/
final class SerializationUtil
{
use StaticClassTrait;
/** @var bool */
public static $isInTestingContext = false;
/**
* @param mixed $data
*
* @return string
*/
public static function serializeAsJson($data): string
{
try {
$serializedData = JsonUtil::encode($data);
} catch (Exception $ex) {
throw new SerializationException(
ExceptionUtil::buildMessage('Serialization failed', ['data' => $data, 'original exception' => $ex]),
$ex
);
}
return $serializedData;
}
/**
* @param string $name
* @param null|bool|int|float|string|JsonSerializable|stdClass|array<mixed> $value
* @param array<string, mixed> $nameToValue
*
* @return void
*/
private static function assertNotExists(string $name, $value, array $nameToValue): void
{
if (self::$isInTestingContext && array_key_exists($name, $nameToValue)) {
throw new SerializationException(
ExceptionUtil::buildMessage(
'Given key already exists in given array',
['name' => $name, 'value' => $value, 'nameToValue' => $nameToValue]
)
);
}
}
/**
* @param string $name
* @param bool|int|float|string|JsonSerializable|stdClass|array<mixed> $value
* @param array<string, mixed> $nameToValue
*
* @return void
*/
public static function addNameValue(string $name, $value, array &$nameToValue): void
{
self::assertNotExists($name, $value, $nameToValue);
$nameToValue[$name] = $value;
}
/**
* @param string $name
* @param null|bool|int|float|string|JsonSerializable|stdClass|array<mixed> $value
* @param array<string, mixed> $nameToValue
*
* @return void
*/
public static function addNameValueAssumeNotNull(string $name, $value, array &$nameToValue): void
{
/** @var bool|int|float|string|JsonSerializable|stdClass|array<mixed> $value */
self::addNameValue($name, $value, /* ref */ $nameToValue);
}
/**
* @param string $name
* @param null|bool|int|float|string|JsonSerializable|stdClass|array<mixed> $value
* @param array<string, mixed> $nameToValue
*
* @return void
*/
public static function addNameValueIfNotNull(string $name, $value, array &$nameToValue): void
{
self::assertNotExists($name, $value, $nameToValue);
if ($value !== null) {
$nameToValue[$name] = $value;
}
}
/**
* @param string $name
* @param array<array-key, mixed>|stdClass $value
* @param array<string, mixed> $nameToValue
*
* @return void
*/
public static function addNameValueIfNotEmpty(string $name, $value, array &$nameToValue): void
{
self::assertNotExists($name, $value, $nameToValue);
if (!empty($value)) {
$nameToValue[$name] = $value;
}
}
public static function prepareForSerialization(?OptionalSerializableDataInterface &$value): int
{
if ($value === null) {
return BoolUtil::INT_FOR_FALSE;
}
if ($value->prepareForSerialization()) {
return BoolUtil::INT_FOR_TRUE;
}
$value = null;
return BoolUtil::INT_FOR_FALSE;
}
/**
* @param float $timestamp
*
* @return float|int
*/
public static function adaptTimestamp(float $timestamp)
{
// If int type is large enough to hold 64-bit (8 bytes) use it instead of float
return (PHP_INT_SIZE >= 8) ? intval($timestamp) : $timestamp;
}
/**
* @param array<string, mixed>|stdClass $nameToValue
*
* @return array<string, mixed>
*/
public static function preProcessResult($nameToValue)
{
return is_array($nameToValue) ? $nameToValue : [];
}
/**
* @param array<string, mixed> $nameToValue
*
* @return array<string, mixed>|stdClass
*/
public static function ensureObject(array $nameToValue)
{
return ArrayUtil::isEmpty($nameToValue) ? (new stdClass()) : $nameToValue;
}
/**
* @param array<string, mixed> $nameToValue
*
* @return array<string, mixed>|stdClass
*/
public static function postProcessResult(array $nameToValue)
{
return self::ensureObject($nameToValue);
}
}