Use the Specification pattern to encapsulate business rules and make them composable.
interface SpecificationInterface
{
public function isSatisfiedBy($candidate): bool;
}
class UserIsAdultSpecification implements SpecificationInterface
{
public function isSatisfiedBy($user): bool
{
return $user->age >= 18;
}
}
class UserHasValidEmailSpecification implements SpecificationInterface
{
public function isSatisfiedBy($user): bool
{
return filter_var($user->email, FILTER_VALIDATE_EMAIL) !== false;
}
}
class AndSpecification implements SpecificationInterface
{
private $specs;
public function __construct(SpecificationInterface ...$specs)
{
$this->specs = $specs;
}
public function isSatisfiedBy($candidate): bool
{
foreach ($this->specs as $spec) {
if (!$spec->isSatisfiedBy($candidate)) {
return false;
}
}
return true;
}
}
// Usage
$validUserSpec = new AndSpecification(
new UserIsAdultSpecification(),
new UserHasValidEmailSpecification()
);
$user = new stdClass();
$user->age = 25;
$user->email = 'user@example.com';
if ($validUserSpec->isSatisfiedBy($user)) {
echo "User is valid";
} else {
echo "User is not valid";
}