Create a small utility (e.g. DeterministicTagReplacer) that does only this:
- Scans the input string once (no catastrophic backtracking).
- Finds candidate tag segments deterministically (strpos/offset loop).Delegates:
matching/validation of a tag
replacement rendering to injected callables.
Then replaceTagDeterministic() becomes a thin wrapper that configures the helper for that specific tag type.
Why this is clean (IPF + PHP best practices)
- Single Responsibility: scanning logic separated from tag-specific transformation.
- Open/Closed: add new tag replacers without changing core scanner.
- Dependency Injection: pass behavior via callable/interface, easy to test.
- Deterministic runtime: index-based scanning avoids regex ReDoS risk.
- Testability: unit test scanner once; unit test each tag strategy independently.
- Type safety: strict types + explicit return signatures.
Suggested shape
libraries/ipf/text/DeterministicTagReplacer.php
<?php
declare(strict_types=1);
namespace ImpressCMS\IPF\Text;
Then in your existing class:
.../YourClass.php
private function replaceTagDeterministic(string $text): string
{
return $this->tagReplacer->replace(
$text,
function (string $input, int $offset): ?array {
// deterministic find + parse for your specific tag
Extra refinements (recommended)
Define small interfaces instead of raw callables if you want stricter IPF style:
TagMatchStrategyInterface
TagRenderStrategyInterface
Add guard clauses for malformed tags and always ensure cursor advances.
Keep multibyte considerations explicit (mb_*) only if your tag syntax requires it.
Add focused tests:
no tag
one tag
multiple tags
malformed/open tag
nested-like patterns
very long adversarial input
Create a small utility (e.g. DeterministicTagReplacer) that does only this:
matching/validation of a tag
replacement rendering to injected callables.
Then replaceTagDeterministic() becomes a thin wrapper that configures the helper for that specific tag type.
Why this is clean (IPF + PHP best practices)
Suggested shape
libraries/ipf/text/DeterministicTagReplacer.php
Then in your existing class:
.../YourClass.php
Extra refinements (recommended)