2017-03-29 17:25:44 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace Amp\Internal;
|
|
|
|
|
2017-04-23 15:29:08 +02:00
|
|
|
/**
|
|
|
|
* Formats a stacktrace obtained via `debug_backtrace()`.
|
|
|
|
*
|
2020-03-28 12:23:46 +01:00
|
|
|
* @param array<array{file?: string, line: int, type?: string, class: string, function: string}> $trace Output of
|
|
|
|
* `debug_backtrace()`.
|
2017-04-23 15:29:08 +02:00
|
|
|
*
|
|
|
|
* @return string Formatted stacktrace.
|
|
|
|
*
|
2017-05-02 18:59:52 +02:00
|
|
|
* @codeCoverageIgnore
|
2017-04-23 15:29:08 +02:00
|
|
|
* @internal
|
|
|
|
*/
|
2018-06-18 20:00:01 +02:00
|
|
|
function formatStacktrace(array $trace): string
|
|
|
|
{
|
2020-03-28 12:23:46 +01:00
|
|
|
return \implode("\n", \array_map(static function ($e, $i) {
|
2017-12-02 17:03:38 +01:00
|
|
|
$line = "#{$i} ";
|
|
|
|
|
|
|
|
if (isset($e["file"])) {
|
|
|
|
$line .= "{$e['file']}:{$e['line']} ";
|
|
|
|
}
|
2017-03-29 17:25:44 +02:00
|
|
|
|
2017-12-07 18:23:19 +01:00
|
|
|
if (isset($e["type"])) {
|
2017-03-29 17:25:44 +02:00
|
|
|
$line .= $e["class"] . $e["type"];
|
|
|
|
}
|
|
|
|
|
|
|
|
return $line . $e["function"] . "()";
|
2017-11-29 13:36:50 +01:00
|
|
|
}, $trace, \array_keys($trace)));
|
2017-04-23 15:29:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a `TypeError` with a standardized error message.
|
|
|
|
*
|
|
|
|
* @param string[] $expected Expected types.
|
2018-06-18 20:00:01 +02:00
|
|
|
* @param mixed $given Given value.
|
2017-04-23 15:29:08 +02:00
|
|
|
*
|
|
|
|
* @return \TypeError
|
|
|
|
*
|
|
|
|
* @internal
|
|
|
|
*/
|
2018-06-18 20:00:01 +02:00
|
|
|
function createTypeError(array $expected, $given): \TypeError
|
|
|
|
{
|
2017-04-23 15:29:08 +02:00
|
|
|
$givenType = \is_object($given) ? \sprintf("instance of %s", \get_class($given)) : \gettype($given);
|
|
|
|
|
|
|
|
if (\count($expected) === 1) {
|
|
|
|
$expectedType = "Expected the following type: " . \array_pop($expected);
|
|
|
|
} else {
|
|
|
|
$expectedType = "Expected one of the following types: " . \implode(", ", $expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
return new \TypeError("{$expectedType}; {$givenType} given");
|
2017-04-24 15:39:08 +02:00
|
|
|
}
|
2018-12-10 20:07:11 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the current time relative to an arbitrary point in time.
|
|
|
|
*
|
|
|
|
* @return int Time in milliseconds.
|
|
|
|
*/
|
|
|
|
function getCurrentTime(): int
|
|
|
|
{
|
2020-03-28 12:23:46 +01:00
|
|
|
/** @var int|null $startTime */
|
2019-05-31 19:48:03 +02:00
|
|
|
static $startTime;
|
2020-03-28 12:23:46 +01:00
|
|
|
/** @var int|null $nextWarning */
|
2019-05-31 20:15:22 +02:00
|
|
|
static $nextWarning;
|
2019-05-31 19:48:03 +02:00
|
|
|
|
2019-05-31 19:48:32 +02:00
|
|
|
if (\PHP_INT_SIZE === 4) {
|
2019-05-31 20:42:02 +02:00
|
|
|
// @codeCoverageIgnoreStart
|
2019-05-31 19:48:03 +02:00
|
|
|
if ($startTime === null) {
|
2019-05-31 19:48:32 +02:00
|
|
|
$startTime = \PHP_VERSION_ID >= 70300 ? \hrtime(false)[0] : \time();
|
2019-05-31 20:15:22 +02:00
|
|
|
$nextWarning = \PHP_INT_MAX - 86400 * 7;
|
2019-05-31 19:48:03 +02:00
|
|
|
}
|
|
|
|
|
2019-05-31 19:48:32 +02:00
|
|
|
if (\PHP_VERSION_ID >= 70300) {
|
|
|
|
list($seconds, $nanoseconds) = \hrtime(false);
|
|
|
|
$seconds -= $startTime;
|
2019-05-31 20:15:22 +02:00
|
|
|
|
|
|
|
if ($seconds >= $nextWarning) {
|
|
|
|
$timeToOverflow = (\PHP_INT_MAX - $seconds * 1000) / 1000;
|
|
|
|
\trigger_error(
|
|
|
|
"getCurrentTime() will overflow in $timeToOverflow seconds, please restart the process before that. " .
|
|
|
|
"You're using a 32 bit version of PHP, so time will overflow about every 24 days. Regular restarts are required.",
|
|
|
|
\E_USER_WARNING
|
|
|
|
);
|
|
|
|
|
2020-03-28 12:23:46 +01:00
|
|
|
/** @psalm-suppress PossiblyNullOperand */
|
2019-05-31 20:15:22 +02:00
|
|
|
$nextWarning += 600; // every 10 minutes
|
|
|
|
}
|
|
|
|
|
2019-05-31 19:48:32 +02:00
|
|
|
return (int) ($seconds * 1000 + $nanoseconds / 1000000);
|
|
|
|
}
|
|
|
|
|
2019-05-31 20:15:22 +02:00
|
|
|
$seconds = \microtime(true) - $startTime;
|
|
|
|
if ($seconds >= $nextWarning) {
|
|
|
|
$timeToOverflow = (\PHP_INT_MAX - $seconds * 1000) / 1000;
|
|
|
|
\trigger_error(
|
|
|
|
"getCurrentTime() will overflow in $timeToOverflow seconds, please restart the process before that. " .
|
|
|
|
"You're using a 32 bit version of PHP, so time will overflow about every 24 days. Regular restarts are required.",
|
|
|
|
\E_USER_WARNING
|
|
|
|
);
|
|
|
|
|
2020-03-28 12:23:46 +01:00
|
|
|
/** @psalm-suppress PossiblyNullOperand */
|
2019-05-31 20:15:22 +02:00
|
|
|
$nextWarning += 600; // every 10 minutes
|
|
|
|
}
|
|
|
|
|
2020-03-28 12:23:46 +01:00
|
|
|
return (int) ($seconds * 1000);
|
2019-05-31 20:42:02 +02:00
|
|
|
// @codeCoverageIgnoreEnd
|
2019-05-31 19:48:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (\PHP_VERSION_ID >= 70300) {
|
|
|
|
list($seconds, $nanoseconds) = \hrtime(false);
|
|
|
|
return (int) ($seconds * 1000 + $nanoseconds / 1000000);
|
2018-12-10 20:07:11 +01:00
|
|
|
}
|
|
|
|
|
2020-03-28 12:23:46 +01:00
|
|
|
return (int) (\microtime(true) * 1000);
|
2018-12-10 20:07:11 +01:00
|
|
|
}
|