Utils component for Waffle framework.

Maintainers

Package info

github.com/waffle-commons/utils

pkg:composer/waffle-commons/utils

Statistics

Installs: 1 181

Dependents: 5

Suggesters: 0

Stars: 1

Open Issues: 0

0.1.0-beta2.1 2026-05-30 18:48 UTC

README

Discord PHP Version Require PHP CI codecov Latest Stable Version Latest Unstable Version Total Downloads Packagist License

Waffle Utils Component

Release: v0.1.0-beta2 ย |ย  CHANGELOG.md

Stateless, pure-function helpers shared across the Waffle ecosystem. The package intentionally has no I/O dependencies and no per-process state โ€” every helper here is safe to use across FrankenPHP worker requests without reset.

๐Ÿ†• Beta-1 change

The former Waffle\Commons\Utils\Trait\ReflectionTrait has been removed and decomposed into three single-responsibility final readonly services (Beta-1 Phase 1 architectural pass โ€” Single Responsibility over trait-based reuse). Consumers inject the service they need instead of mixing in a trait.

๐Ÿ“ฆ Installation

composer require waffle-commons/utils

๐Ÿงฑ Surface

Class Role
Waffle\Commons\Utils\Service\ClassParser Tokenizer-based class introspection. className(string $path): string reads a PHP file with token_get_all() (no regex, no eval) and returns the fully qualified class/interface/trait/enum name, or '' if none. Used by routing's RouteDiscoverer / ControllerFinder.
Waffle\Commons\Utils\Service\AttributeReader newAttributeInstance(object $target, string $attribute): object resolves an attribute instance from a target, falling back to a zero-arg instance when the target carries no matching attribute (preserving the former trait's contract).
Waffle\Commons\Utils\Service\ReflectionInspector Object-shape inspection: isFinal(), isInstance(), getProperties(), getMethods().

The package grows only when a helper is genuinely shared across more than one component.

๐Ÿ” ClassParser

Reads a PHP file with token_get_all() (no regex, no eval) and returns the fully qualified class/interface/trait/enum name found inside, or an empty string if none is present.

use Waffle\Commons\Utils\Service\ClassParser;

$parser = new ClassParser();
$fqcn = $parser->className('/path/to/UserController.php'); // 'App\Controller\UserController'

The implementation handles:

  • Bracketed (namespace App { โ€ฆ }) and statement (namespace App;) namespace forms.
  • PHP 8.x final, readonly, abstract modifiers in front of class/interface/trait/enum.
  • Anonymous classes โ€” they are skipped (returns the first non-anonymous declaration).

๐Ÿ˜ PHP 8.5 surface

All three services are final readonly class with strict types and explicit return types throughout. They hold no mutable state and are safe to reuse across FrankenPHP worker requests.

๐Ÿงญ Architectural boundary (mago guard)

An active dependency perimeter is enforced on every CI run by vendor/bin/mago guard (bundled into composer mago; zero baselines). The rules live in mago.toml under [guard.perimeter] โ€” a forbidden use statement fails the build, not a reviewer.

Production code under Waffle\Commons\Utils may depend only on:

  • Waffle\Commons\Utils\** โ€” itself
  • Waffle\Commons\Contracts\** โ€” the shared contracts package, the only Waffle dependency permitted
  • Psr\** โ€” PSR interfaces
  • @global + Psl\** โ€” PHP core and the PHP Standard Library

Test code under WaffleTests\Commons\Utils is unrestricted (@all). Structural rules are guarded too: interfaces must be named *Interface, Exception\** classes must end in *Exception, and any Enum\** namespace may hold only enum declarations.

Contract-first, component-agnostic by construction: components compose through waffle-commons/contracts, never directly through one another.

๐Ÿงช Testing

docker exec -w /waffle-commons/utils waffle-dev composer tests

๐Ÿ“„ License

MIT โ€” see LICENSE.md.