Download the PHP package bakame/aide-profiler without Composer
On this page you can find all versions of the php package bakame/aide-profiler. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download bakame/aide-profiler
More information about bakame/aide-profiler
Files in bakame/aide-profiler
Package aide-profiler
Short Description A minimalist, embeddable, multi-metric, and framework-agnostic profiler for PHP
License MIT
Informations about the package aide-profiler
Stackwatch
Stackwatch is a lightweight profiler for PHP 8.1+. It helps you measure performance with precision—without unnecessary complexity.
Stackwatch bridges the gap between basic timers and heavy profiling tools like PHPBench, Xdebug or Blackfire. It is perfect for:
- Isolated performance testing
- Annotated profiling of large codebases
- Lightweight integration into dev workflows
Zero-dependency core. Optional CLI with familiar Symfony Console integration.
Installation
composer require bakame/stackwatch
You need:
- PHP >= 8.1 but the latest stable version of PHP is recommended
symfony/console
andsymfony/process
if you are going to use the CLI commandpsr/log
is optional
Usage
Traditionally, profiling a section of code quickly looks like this:
Stackwatch streamlines this process by removing the need for manual timing and setup, making profiling more convenient and consistent.
The package offers three (3) complementary ways to profile your code, it features:
- Scoped Execution Profiling – profile any block using closures
- Timeline-Based Profiling – segment code with named checkpoints
- Attribute-Driven CLI Profiling – run code marked with #[Profile] via a CLI command
Profiler
Metrics quick access
Let's adapt the first example using the Profiler
class.
`
The method returns a Metrics
class with readonly properties for each metric.
`
All duration values are expressed in nanoseconds, while memory-related metrics are measured in bytes.
You can retrieve the Metrics
statistics in a human-readable format using the instance forHuman()
method.
You can either:
- Call the method without arguments to retrieve all metrics as formatted strings in an associative
array
. - Or pass the name of a specific metric to retrieve only that value, formatted for human readability.
Iterations
To calculate the average usage of a specific metric, specify the number of iterations as the second argument. The callback will be executed accordingly, and the method will return the average value over all iterations:
`
Full report
If you need access to the complete set of statistical data rather than just average values, use the Profiler::report
method.
This method returns a Report
instance instead of a Metrics
object. The Report
aggregates detailed statistics for each metric,
offering a full performance profile. The Report
class exposes the same properties as the Metrics
class but the type differs.
Each property of the Report
is a Statistics
instance.
The Statistics
class represents a full statistical summary computed from a set of numeric values. It provides key metrics
such as minimum, maximum, sum, average, median, variance, standard deviation, and coefficient of variation.
Each instance is associated with a Unit (e.g., bytes, nanoseconds) to ensure values are consistently interpreted
and formatted.
Each
Statistics` instance provides:
toArray
– for machine-readable dataforHuman
– for formatted, human-friendly output- implements the
JsonSerializable
interface to enable easy JSON export
Use this structure to analyze performance in depth, log profiles, or visualize trends over time.
Accessing the result
Finally, the static method Profiler::execute
allows you to retrieve both the result of a callback
execution and its profiling data. It returns a ProfiledResult
instance, where the result
property contains the callback’s return value, and the summary
property holds the
profiling metrics collected during the call.
`
Metrics recording
Beyond its static methods, the Profiler
also supports recording multiple individual calls.
To enable this, create a new Profiler
instance by passing in the callback you wish to profile.
`
You can execute the Profiler
instance as many times as needed — it will record all
execution metrics each time.
You can access any Summary
by index using the nth
method, or use the first
and latest
methods
to quickly retrieve the first and last recorded Summary
. The nth
method also accepts negative
integers to simplify access from the end of the list.
Using labels
To add a custom label to each run, use the profile
method. This method works like the
run
method but allows you to assign a custom label to the returned Summary
object
via its first argument.
`
You can reuse the same label multiple times. The Profiler::get()
method returns the most recent
entry associated with the specified label. In contrast, Profiler::getAll()
returns an array
of all entries recorded under that label, ordered from oldest to newest.
If the label is invalid or has never been used, Profiler::getAll()
returns an empty array
while Profiler::get()
returns null
. To determine whether a label exists, use Profiler::has()
,
which returns true
if the label has been recorded, or false
otherwise.
Resetting the Profiler
At any given time you can reset the Profiler
by clearing all the Summary
already recorded.
Timeline
In situation where you can't work with callbacks you can alternatively use the Timeline
class.
The Timeline
class profiles across labeled checkpoints ("snapshots") in your
code. A Timeline
class is a sequence of snapshots of your codebase.
You can start a new Timeline
using the static method start
:
When starting a timeline with the start
method, you initiate a new Timeline
class but you
also immediately capture a significant point in your code also known as a snapshot.
Taking Snapshots
Use capture()
to mark significant points in your code. Those points must each have a unique identifier
called label
. Labels are automatically normalized (e.g., trimmed, validated).
Getting profiling results
To get a high-level profile between the first and lastest snapshot use the summarize
method.
You can provide a custom label for the summary:
If needed, you can measure the profiling data between two specific labels:
If you do not specify the second label, the method will default to using the next snapshot to the one specified as the first argument.
You can iterate over each successive pair of snapshots to return the consecutive deltas:
You can also take a snapshot and directly return the calculated summary between the Timeline
first snapshot and the one you just take using the take
method
Just like with the summary
method you can provide an optional custom label for the summary report:
Finalizing the Timeline
While not mandatory or required, The complete
method finalizes the profiling timeline, marking it
as complete and preventing any further snapshots or operations that modify the state.
Before calling complete
, the timeline is open and can accept snapshots via capture
or take
methods. Once complete
is called:
- The timeline becomes complete and is closed to further modifications.
- Further calls to
capture
ortake
will throw anUnableToProfile
exception. - Calling
complete
multiple times has no effects - it is idempotent. - The result of
summarize
remains unchanged after completion and can be safely called multiple times.
At any given time you can check your Timeline
completion status using the Timeline::isComplete
method which returns true
when it is complete; false otherwise.
Timeline utility methods
The Timeline
instance also gives you access to other utility methods:
[!IMPORTANT]
Thereset()
method reopens the timeline and clears all recorded snapshots, enabling it to be reused for a new profiling session.
As an example, you can do the following:
And we can adapt the first example using the Timeline
class this time.
`
Identifier
Every Timeline
and Profiler
instance has a unique identifier accessible via the identifier
method.
If not provided, an internal label generator will assign a unique name to the property. The identifier can be used for logging, debugging or for correlation when multiple profilers and/or timelines are running in parallel.
Logging
The Profiler
and Timeline
classes can optionally log profiling activity using any logger that
implements Psr\Log\LoggerInterface
.
To enable this feature, you must install and configure a PSR-3
-compatible logger. Common
implementations include Monolog
, Laminas\Log
, Symfony’s or Laravel logger
component, and others.
[!TIP]
Logging can be done also on theProfiler
static methods, they all optionally accept aLoggerInterface
argument. When logging timeline or profiler instances their respective identifier is added to the log to ease identifying which instance is generating the log entries.
Outside the Profiler
and the Timeline
you can use the package features through a CLI command.
CLI command
A CLI Command is available to allow you to benchmark PHP functions and methods located in a
specific file or directory using the custom #[Bakame\Stackwatch\Profile]
attribute.
This is especially useful for:
- Automating performance regressions in CI pipelines
- Profiling code outside the context of an application
Usage
Option | Description |
---|---|
-p, --path=PATH |
Path to scan for PHP files to profile (required) |
-o, --output=OUTPUT |
Path to store the profiling output (optional) |
-f, --format=FORMAT |
Output format: 'table' or 'json' (default: 'table') |
-d, --depth=DEPTH |
Recursion depth (0 = current dir only, default: unlimited) (optional) |
-n, --no-recursion |
Disable directory recursion (optional) |
-x, --isolation |
To profile by isolation each file |
-P, --pretty |
Pretty-print the JSON/NDJSON output (json only) |
-i, --info |
Show additional system/environment information |
-h, --help |
Display the help message |
-V, --version |
Display the version and exit |
-t, --tags |
filter the target to profile using tags (ie --tags=web) (optional) |
Example
let's assume you have the following file located in /path/profiler/test.php
.
If you run the following command:
It will output the following:
- the first table shows the average metrics for the
Foobar::test
method. - the second table shows the fully detailed report on the function
test
.
The Profile attribute
The #[Profile]
attribute marks a function, method, or class for performance profiling during execution.
When applied, the profiler will repeatedly execute the target code to collect detailed runtime metrics,
allowing developers to analyze and optimize code performance with statistically meaningful data.
The attribute can be applied to:
- Standalone functions
- Class methods, regardless of visibility (
public
,protected
, orprivate
) - Classes — When applied at the class level, all methods of that class will be profiled using the class-level attribute configuration.
[!NOTE] If a method within a class is also marked with its own #[Profile] attribute, the method-level attribute configuration overrides the class-level configuration for that specific method.
[!IMPORTANT] Functions or methods that declare one or more arguments will not be profiled. Only functions or methods without parameters can be profiled using this attribute.
Options
Option | Type | Required | Description |
---|---|---|---|
type |
string |
Yes | Level of detail in the profiling output. Possible values: Profile::SUMMARY or Profile::DETAILED . |
iterations |
int |
Yes | Number of times the function/method will be executed to gather profiling data. Must be > 0. |
warmup |
int |
No | Number of initial "warmup" executions excluded from measurements (default: 0). Useful to stabilize results. |
tags |
list<string> |
No | List of tags to filter or categorize profiled functions/methods. |
Option Details
iterations
: Controls how many times the target will be run during profiling to ensure statistical significance. Larger values provide more accurate metrics but increase profiling time.warmup
: Allows the profiler to run the target code several times before recording metrics, which helps mitigate effects like JIT compilation or caching impacting the results.type
:Profile::SUMMARY
: Outputs core statistics such as average execution time.Profile::DETAILED
: Tags enable grouping and filtering in profiling reports, helping users focus on specific categories or subsets of profiled code.
tags
: Tags enable grouping and filtering in profiling reports, helping users focus on specific categories or subsets of profiled code.
Examples
On a function
On a method
On a class
Notes
- If
warmup
is omitted, it defaults to 0 (no warmup). - The
tags
array can be empty or omitted if filtering is not needed. - Be mindful of the performance impact during profiling, especially with high iteration counts.
- Functions or methods with arguments are ignored.
All required dependencies should be loaded in the target file (use require
, include
or Composer autoload).
Integration into CI
You can run the profiling command in your CI pipelines to detect regressions or performance anomalies.
[!IMPORTANT]
The command line requiressymfony\console
and thepsr\log
interfaces to work.[!CAUTION]
The command line can scan your full codebase if you specify a directory instead of a path. The json output is a NDJSON each line representing the result of a successful file scan.
Exporters
The package can help with exporting its metrics using different mechanisms.
JSON
Both the Profiler
and Timeline
classes support JSON export via PHP's json_encode
function.
This allows you to serialize profiling data for inspection, storage, or transmission.
Calling json_encode($profiler)
will produce a JSON object containing:
identifier
: the profiler's unique identifiersummaries
: an array of summary entries, ordered from oldest to latest
Each summary entry includes:
label
: the associated label or name of the profiling blocksnapshots
: an array of two snapshots (start and end), ordered chronologicallymetrics
: computed performance metrics between the two snapshots
See a sample profiler JSON output for a complete structure.
Calling json_encode($timeline)
will produce a JSON object containing:
identifier
: the timeline's unique identifiersnapshots
: an array of snapshot entries, ordered from oldest to latest
See a sample timeline JSON output for a complete structure.
In order to facilitate JSON export, the package has a dedicated JsonExporter
class
which will be able to store the generated json in the specified location. It supports
streams, string path and SplFileInfo
objects.
The report will be stored in the designated location.
[!IMPORTANT]
If you try to store multiple export in the same file (specified by a string) They will get overwritten and only the last export will be stored. To get the data appended provide an already openresource
orSplFileObject
.
CLI
If you have the symfony\console
package installed in your application, you can display
the Profiler
or the Timeline
recorded data recorded using the ConsoleExporter
class.
the following table will be outputted in your terminal.
Open Telemetry
The Profiler
and the Timeline
results can be exported to an Open telemetry compatible
server using the open-telemetry/exporter-otlp
package.
To do so, first install the package if it is not yet the case, then do the following:
Remember to change the $tracerProvider
to connect to your own environment and server.
Helpers
Environment
The package includes an Environment
class that collects information about the current system for profiling purposes.
Apart from returning raw information about your system, the instance can be used to detect the PHP architecture used or if the memory is unlimited using boolean returning methods:
`
The ConsoleExporter
also provides an exporter for the class:
Will return
Unit of Measurement
To correctly show the memory and duration unit, the package comes with 2 helper Enum:
MemoryUnit
to help formatting and converting to and from bytes.DurationUnit
to help formatting and converting to and from nanoseconds.
Testing
The library has:
- a PHPUnit test suite.
- a coding style compliance test suite using PHP CS Fixer.
- a code analysis compliance test suite using PHPStan.
To run the tests, run the following command from the project folder.
Contributing
Contributions are welcome and will be fully credited. Please see CONDUCT for details.
Security
If you discover any security related issues, please email [email protected] instead of using the issue tracker.
Changelog
Please see CHANGELOG for more information on what has changed recently.