Skip to content

Filters

Use a filter when several parts of your application may adjust the same value. Register callbacks with addFilter(), pass the starting value to applyFilters(), and use the returned value.

A useful example is a display title that different integrations can localize or annotate.

The filter methods have two jobs:

Method Use it for Returns
addFilter() Registering a value transformation. A RegistrationHandle.
applyFilters() Passing a value through the filter chain. The final value, or the original value when empty.

addFilter()

public function addFilter(
  string $hookPoint,
  array|callable $callback,
  int $priority = 10,
): RegistrationHandle
Use it when:

you want one module to contribute a transformation to a named value.

Applies to: Filters

Returns: A handle for this exact registration.

With no listeners: The filter is stored, but no callback runs until applyFilters() is called.

Exceptions: Callback and resolver exceptions surface when the filter is invoked.

Configuration: Yes. The callback remains registered until removed.

applyFilters()

public function applyFilters(
  string $hookPoint,
  mixed $value,
  mixed ...$arguments,
): mixed
Use it when:

you want to pass a value through ordered transformations.

Applies to: Filters

Returns: The value returned by the last filter.

With no listeners: The original value is returned unchanged.

Exceptions: Exceptions from listeners bubble to the caller.

Configuration: No. It invokes the current listener snapshot.

The default priority is 10. Lower priorities run earlier, so priority is part of the order contract when one transformation depends on another.

The current value is always the first callback argument. Any additional arguments follow it:

use Magdicom\Hooks;
$hooks = new Hooks();
$hooks->addFilter('email.subject', static function (string $title, string $locale): string {
return $locale === 'en' ? $title : '[' . $locale . '] ' . $title;
});
$displayTitle = $hooks->applyFilters('email.subject', 'Release notes', 'en');

The first callback receives 'Release notes' as $title and 'en' as $locale. A later callback receives the first callback’s returned string as its new $title.

Each callback returns the value passed to the next callback. That lets you keep each transformation small:

<?php
declare(strict_types=1);
use Magdicom\Hooks;
$hooks = new Hooks();
$hooks->addFilter('email.subject', static fn (string $value): string => trim($value));
$hooks->addFilter('email.subject', static fn (string $value): string => strtolower($value), priority: 20);
$subject = $hooks->applyFilters('email.subject', ' Hooks Docs ');
// 'hooks docs'

Lower priorities run first. Equal-priority filters keep registration order. The default is 10; choose another priority when the order is part of your hook point’s contract.

With no listeners, applyFilters() returns the original $value. Hooks does not transform or consume the additional arguments; it only passes them to registered callbacks.

addFilter() returns a RegistrationHandle, which is the simplest way to remove one exact registration:

<?php
declare(strict_types=1);
use Magdicom\Hooks;
$hooks = new Hooks();
$handle = $hooks->addFilter('email.subject', static fn (string $title): string => strtoupper($title));
$handle->remove();
$title = $hooks->applyFilters('email.subject', 'Release notes');
// 'Release notes'

The handle’s remove() method returns true once and false after removal. Callback-based removeFilter() matches the callback and priority. removeAllFilters(?string $hookPoint = null) removes filters for one point or, when omitted, all filter registrations.

Use actions when return values are irrelevant, and collectors when each listener should keep an independent result.