HEX
Server: Apache
System: Linux efa57bbe-abb1-400d-2985-3b056fbc2701.secureserver.net 6.1.147-1.el9.elrepo.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Jul 24 12:33:32 EDT 2025 x86_64
User: root (0)
PHP: 8.0.30.4
Disabled: NONE
Upload Files
File: //var/www/wp-content/mu-plugins/object-cache-pro/src/Metrics/Measurements.php
<?php
/**
 * Copyright © 2019-2024 Rhubarb Tech Inc. All Rights Reserved.
 *
 * The Object Cache Pro Software and its related materials are property and confidential
 * information of Rhubarb Tech Inc. Any reproduction, use, distribution, or exploitation
 * of the Object Cache Pro Software and its related materials, in whole or in part,
 * is strictly forbidden unless prior permission is obtained from Rhubarb Tech Inc.
 *
 * In addition, any reproduction, use, distribution, or exploitation of the Object Cache Pro
 * Software and its related materials, in whole or in part, is subject to the End-User License
 * Agreement accessible in the included `LICENSE` file, or at: https://objectcache.pro/eula
 */

declare(strict_types=1);

namespace RedisCachePro\Metrics;

use Countable;
use Traversable;
use ArrayAccess;
use ArrayIterator;
use IteratorAggregate;

/**
 * @implements \ArrayAccess<int, \RedisCachePro\Metrics\Measurement>
 * @implements \IteratorAggregate<\RedisCachePro\Metrics\Measurement>
 */
class Measurements implements ArrayAccess, Countable, IteratorAggregate
{
    /**
     * The measurements contained in the collection.
     *
     * @var \RedisCachePro\Metrics\Measurement[]
     */
    protected $items = [];

    /**
     * The cached results of extracted metric values.
     *
     * @var array<mixed>
     */
    protected $cache = [];

    /**
     * Get all of the items in the collection.
     *
     * @return \RedisCachePro\Metrics\Measurement[]
     */
    public function all()
    {
        return $this->items;
    }

    /**
     * Count the number of items in the collection.
     *
     * @return int
     */
    public function count(): int
    {
        return count($this->items);
    }

    /**
     * Returns an array of metric values.
     *
     * @param  string  $metric
     * @return array<mixed>
     */
    public function metricValues(string $metric)
    {
        if (isset($this->cache[$metric])) {
            return $this->cache[$metric];
        }

        $this->cache[$metric] = array_filter(
            array_map(static function ($item) use ($metric) {
                return $item->{$metric};
            }, $this->items),
            function ($value) {
                return ! is_null($value);
            }
        );

        return $this->cache[$metric];
    }

    /**
     * Execute a callback over each item.
     *
     * @param  callable  $callback
     * @return $this
     */
    public function each(callable $callback)
    {
        foreach ($this->items as $key => $item) {
            if ($callback($item, $key) === false) {
                break;
            }
        }

        return $this;
    }

    /**
     * Run a filter over each of the items.
     *
     * @param  callable  $callback
     * @return self
     */
    public function filter(callable $callback)
    {
        $this->items = array_filter($this->items, $callback);

        return $this;
    }

    /**
     * Get the latest value of a given metric.
     *
     * @param  string  $metric
     * @return mixed
     */
    public function latest(string $metric)
    {
        foreach (array_reverse($this->items) as $item) {
            if (! is_null($item->{$metric})) {
                return $item->{$metric};
            }
        }
    }

    /**
     * Get the average value of a given metric.
     *
     * @param  string  $metric
     * @return mixed
     */
    public function max(string $metric)
    {
        $values = $this->metricValues($metric);

        if (count($values)) {
            return max($values);
        }
    }

    /**
     * Get the average value of a given metric.
     *
     * @param  string  $metric
     * @return mixed
     */
    public function mean(string $metric)
    {
        $values = $this->metricValues($metric);

        if ($count = count($values)) {
            return array_sum($values) / $count;
        }
    }

    /**
     * Get the median of a given metric.
     *
     * @param  string  $metric
     * @return mixed
     */
    public function median(string $metric)
    {
        $values = $this->metricValues($metric);

        $count = count($values);

        if ($count === 0) {
            return;
        }

        sort($values);

        $middle = (int) floor($count / 2);

        if ($count % 2) {
            return $values[$middle];
        }

        return ($values[$middle - 1] + $values[$middle]) / 2;
    }

    /**
     * Get the given percentile of a given metric.
     *
     * @param  string  $metric
     * @param  int  $percentile
     * @return mixed
     */
    public function percentile(string $metric, int $percentile)
    {
        $values = $this->metricValues($metric);

        $count = count($values);

        if ($count === 0) {
            return;
        }

        sort($values);

        $index = ($percentile / 100) * ($count - 1);

        if (floor($index) == $index) {
            return $values[$index];
        }

        return ($values[(int) floor($index)] + $values[(int) ceil($index)]) / 2;
    }

    /**
     * Get the 90th percentile of a given metric.
     *
     * @param  string  $metric
     * @return mixed
     */
    public function p90(string $metric)
    {
        return $this->percentile($metric, 90);
    }

    /**
     * Get the 95th percentile of a given metric.
     *
     * @param  string  $metric
     * @return mixed
     */
    public function p95(string $metric)
    {
        return $this->percentile($metric, 95);
    }

    /**
     * Get the 99th percentile of a given metric.
     *
     * @param  string  $metric
     * @return mixed
     */
    public function p99(string $metric)
    {
        return $this->percentile($metric, 99);
    }

    /**
     * Split the measurements into the time-based intervals.
     *
     * @param  int  $interval
     * @return array<int, mixed>
     */
    public function intervals(int $interval)
    {
        $intervals = [];
        $iterator = $this->getIterator();

        while ($iterator->valid()) {
            $item = $iterator->current();
            $timestamp = (int) $item->timestamp - (int) $item->timestamp % $interval;

            if (! isset($intervals[$timestamp])) {
                $intervals[$timestamp] = new self;
            }

            $intervals[$timestamp]->push($item);

            $iterator->next();
        }

        return $intervals;
    }

    /**
     * Get the values of a given key.
     *
     * @param  string  $metric
     * @return array<mixed>
     */
    public function pluck(string $metric)
    {
        return array_map(static function ($item) use ($metric) {
            return $item->{$metric};
        }, $this->items);
    }

    /**
     * Push one or more items onto the end of the collection.
     *
     * @param  \RedisCachePro\Metrics\Measurement  ...$metrics
     * @return self
     */
    public function push(Measurement ...$metrics): self
    {
        array_push($this->items, ...$metrics);

        return $this;
    }

    /**
     * Get an iterator for the items.
     *
     * @return \ArrayIterator<int, \RedisCachePro\Metrics\Measurement>
     */
    public function getIterator(): Traversable
    {
        return new ArrayIterator($this->items);
    }

    /**
     * Determine if an item exists at an offset.
     *
     * @param  int  $key
     * @return bool
     */
    public function offsetExists($key): bool
    {
        return isset($this->items[$key]);
    }

    /**
     * Get an item at a given offset.
     *
     * @param  int  $key
     * @return \RedisCachePro\Metrics\Measurement
     */
    #[\ReturnTypeWillChange]
    public function offsetGet($key)
    {
        return $this->items[$key];
    }

    /**
     * Set the item at a given offset.
     *
     * @param  int  $key
     * @param  \RedisCachePro\Metrics\Measurement  $value
     * @return void
     */
    public function offsetSet($key, $value): void // phpcs:ignore PHPCompatibility
    {
        if (is_null($key)) {
            $this->items[] = $value;
        } else {
            $this->items[$key] = $value;
        }
    }

    /**
     * Unset the item at a given offset.
     *
     * @param  int  $key
     * @return void
     */
    public function offsetUnset($key): void // phpcs:ignore PHPCompatibility
    {
        unset($this->items[$key]);
    }
}