Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## 2.2.1 under development

- Enh #132: Add benchmarks, improve performance of `Message::parse()` (@samdark)
- Bug #130: Updated `Message::parse()` to correctly support multiple placeholders (@technicated)
- Chg #130, #133: Changed `Message::parse()` to conform to PSR-3 (@technicated, @vjik)

Expand Down
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
},
"require-dev": {
"maglnet/composer-require-checker": "^4.4",
"phpbench/phpbench": "^1.0",
"phpunit/phpunit": "^9.6.23",
"rector/rector": "^2.0.17",
"roave/infection-static-analysis-plugin": "^1.25",
Expand Down Expand Up @@ -82,6 +83,7 @@
},
"scripts": {
"test": "phpunit --testdox --no-interaction",
"test-watch": "phpunit-watcher watch"
"test-watch": "phpunit-watcher watch",
"bench": "phpbench run --report=default"
}
}
7 changes: 7 additions & 0 deletions phpbench.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"runner.bootstrap": "vendor/autoload.php",
"runner.path": "tests/Benchmark",
"runner.revs": 1000,
"runner.iterations": 10,
"runner.retry_threshold": 2
}
4 changes: 4 additions & 0 deletions src/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ private function parse(string|Stringable $message, array $context): string
{
$message = (string) $message;

if (!str_contains($message, '{')) {
Copy link
Member Author

@samdark samdark Jan 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there are no placeholders at all, which is quite common, do not run preg_replace_callback(). Gives about a 10—13% performance increase.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has preg_replace_callback() been replaced with strtr()?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No.

return $message;
}

/** @var string */
return preg_replace_callback(
'/\{([\w\.\\\\_]+)\}/',
Expand Down
43 changes: 43 additions & 0 deletions tests/Benchmark/LoggerBench.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Log\Tests\Benchmark;

use Psr\Log\LogLevel;
use Yiisoft\Log\Logger;
use Yiisoft\Log\Target;

final class LoggerBench
{
private Logger $logger;

public function __construct()
{
$this->logger = new Logger([new class () extends Target {
protected function export(): void
{
// noop
}
}]);
}

public function benchLogSimple(): void
{
$this->logger->log(LogLevel::INFO, 'simple message');
}

public function benchLogWithPlaceholder(): void
{
$this->logger->log(LogLevel::INFO, 'has {foo} placeholder', ['foo' => 'some']);
}

public function benchLogWithMultiplePlaceholders(): void
{
$this->logger->log(
LogLevel::INFO,
'Placeholder 1: {p1} - Placeholder 2: {p2}',
['p1' => 'hello', 'p2' => 'world'],
);
}
}
55 changes: 55 additions & 0 deletions tests/Benchmark/MessageBench.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Log\Tests\Benchmark;

use Psr\Log\LogLevel;
use Yiisoft\Log\Message;

final class MessageBench
{
public function benchNoPlaceholder(): void
{
new Message(LogLevel::INFO, 'no placeholder', ['foo' => 'some']);
}

public function benchSinglePlaceholderScalar(): void
{
new Message(LogLevel::INFO, 'has {foo} placeholder', ['foo' => 'some']);
}

public function benchPlaceholderMissing(): void
{
new Message(LogLevel::INFO, 'has {foo} placeholder', []);
}

public function benchPlaceholderNull(): void
{
new Message(LogLevel::INFO, 'has "{foo}" placeholder', ['foo' => null]);
}

public function benchPlaceholderArray(): void
{
new Message(LogLevel::INFO, 'has "{foo}" placeholder', ['foo' => ['bar' => 7]]);
}

public function benchNestedPlaceholder(): void
{
new Message(LogLevel::INFO, 'has "{foo.bar}" placeholder', ['foo' => ['bar' => 7]]);
}

public function benchDeeplyNestedPlaceholder(): void
{
new Message(LogLevel::INFO, 'has "{foo.bar.baz}" placeholder', ['foo' => ['bar' => ['baz' => 7]]]);
}

public function benchMultiplePlaceholders(): void
{
new Message(
LogLevel::INFO,
'Placeholder 1: {p1} - Placeholder 2: {p2}',
['p1' => 'hello', 'p2' => 'world'],
);
}
}
Loading