phpdevcommunity / php-options-resolver
Strict, Fluent, and Type-Safe Option Validation for PHP.
Installs: 400
Dependents: 1
Suggesters: 0
Security: 0
Stars: 1
Watchers: 2
Forks: 0
Open Issues: 0
pkg:composer/phpdevcommunity/php-options-resolver
Requires
- php: >=7.4
- ext-mbstring: *
Requires (Dev)
- depo/unitester: ^1.0.0
README
Strict, Fluent, and Type-Safe Option Validation for PHP.
Stop guessing what's in your $options array. This library provides a robust, fluent API to define, validate, and resolve options with strict type enforcement and custom validation logic. Designed for developers who value clarity and code quality.
Installation
To install this library, use Composer
composer require phpdevcommunity/php-options-resolver
Requirements
- PHP version 7.4 or higher
Documentation (English)
Basic Usage
Define the options for your class using OptionsResolver with the expected options. You can use static factory methods on the Option class to define types easily.
<?php use PhpDevCommunity\Resolver\Option; use PhpDevCommunity\Resolver\OptionsResolver; class Database { private array $options; public function __construct(array $options = []) { $resolver = new OptionsResolver([ Option::string('host')->setOptional('localhost'), Option::string('username')->required(), Option::string('password')->required(), Option::string('dbname')->required(), Option::int('port')->setOptional(3306), ]); $this->options = $resolver->resolve($options); } } // Example usage: try { $database = new Database([ 'username' => 'root', 'password' => 'secret', 'dbname' => 'app_db', ]); // 'host' will be 'localhost' and 'port' will be 3306 } catch (InvalidArgumentException $e) { echo "Error: " . $e->getMessage(); }
Available Types
The Option class provides several static factory methods to enforce types automatically. Here are examples for each type:
String
Option::string('host')->setOptional('localhost');
Integer
Option::int('port')->setOptional(3306);
Float
Option::float('timeout')->setOptional(2.5);
Boolean
Option::bool('active')->setOptional(true);
Array
Option::array('tags')->setOptional(['php', 'library']);
Iterable
Option::iterable('items')->required();
Mixed (No type enforcement)
Option::mixed('metadata')->setOptional(null);
Required vs Optional
- Required: Use
required()to enforce that an option must be passed. If missing, an exception is thrown. - Optional: Use
setOptional($defaultValue)to define a default value if the option is not provided.
Option::string('apiKey')->required(); // Must be provided Option::bool('debug')->setOptional(false); // Defaults to false if missing
Custom Validation
You can add custom validation logic using the validator() method. The closure must return a bool.
Option::string('driver') ->setOptional('mysql') ->validator(function ($value) { return in_array($value, ['mysql', 'pgsql', 'sqlite']); });
Handling Errors
The resolve() method throws an InvalidArgumentException if:
- A required option is missing.
- An undefined option is provided.
- An option value is invalid (wrong type or failed custom validation).
Conditional Requirements
You can make an option required only if another option has a specific value using addRequiredIf.
$resolver = new OptionsResolver([ Option::bool('has_database')->setOptional(false), Option::string('db_host')->setOptional(null), ]); // 'db_host' becomes required only if 'has_database' is true $resolver->addRequiredIf('db_host', 'has_database', true);
Deprecating Options
You can mark an option as deprecated. A E_USER_DEPRECATED error will be triggered if the option is used.
Option::string('old_option')->deprecate('Use "new_option" instead.');
Additional Constraints
The library provides helpers for common constraints like min and max. These work for strings (length), numbers (value), and arrays (count).
Option::string('username')->min(3)->max(20); Option::int('age')->min(18); Option::array('tags')->max(5);
Multiple Validators
You can chain multiple validators. All of them must pass.
Option::string('code') ->validator(fn($v) => str_starts_with($v, 'A')) ->validator(fn($v) => str_ends_with($v, 'Z'));
License
This project is licensed under the MIT License. See the LICENSE file for details.
Documentation (Français)
Usage de base
Définissez les options attendues pour votre classe en utilisant OptionsResolver. Vous pouvez utiliser les méthodes statiques de la classe Option pour définir les types facilement.
<?php use PhpDevCommunity\Resolver\Option; use PhpDevCommunity\Resolver\OptionsResolver; class Database { private array $options; public function __construct(array $options = []) { $resolver = new OptionsResolver([ Option::string('host')->setOptional('localhost'), Option::string('username')->required(), Option::string('password')->required(), Option::string('dbname')->required(), Option::int('port')->setOptional(3306), ]); $this->options = $resolver->resolve($options); } } // Exemple d'utilisation : try { $database = new Database([ 'username' => 'root', 'password' => 'secret', 'dbname' => 'app_db', ]); // 'host' vaudra 'localhost' et 'port' vaudra 3306 } catch (InvalidArgumentException $e) { echo "Erreur : " . $e->getMessage(); }
Types Disponibles
La classe Option fournit plusieurs méthodes statiques pour forcer les types automatiquement. Voici des exemples pour chaque type :
Chaîne de caractères (String)
Option::string('host')->setOptional('localhost');
Entier (Integer)
Option::int('port')->setOptional(3306);
Flottant (Float)
Option::float('timeout')->setOptional(2.5);
Booléen (Boolean)
Option::bool('active')->setOptional(true);
Tableau (Array)
Option::array('tags')->setOptional(['php', 'library']);
Itérable (Iterable)
Option::iterable('items')->required();
Mixte (Mixed - Pas de vérification de type)
Option::mixed('metadata')->setOptional(null);
Requis vs Optionnel
- Requis : Utilisez
required()pour obliger l'utilisateur à fournir une option. Si elle est manquante, une exception est levée. - Optionnel : Utilisez
setOptional($defaultValue)pour définir une valeur par défaut si l'option n'est pas fournie.
Option::string('apiKey')->required(); // Doit être fourni Option::bool('debug')->setOptional(false); // Vaut false par défaut si absent
Validation Personnalisée
Vous pouvez ajouter une logique de validation personnalisée via la méthode validator(). La closure doit retourner un bool.
Option::string('driver') ->setOptional('mysql') ->validator(function ($value) { return in_array($value, ['mysql', 'pgsql', 'sqlite']); });
Gestion des Erreurs
La méthode resolve() lance une InvalidArgumentException si :
- Une option requise est manquante.
- Une option non définie est fournie.
- Une valeur d'option est invalide (mauvais type ou échec de validation personnalisée).
Prérequis Conditionnels
Vous pouvez rendre une option obligatoire uniquement si une autre option a une valeur spécifique en utilisant addRequiredIf.
$resolver = new OptionsResolver([ Option::bool('has_database')->setOptional(false), Option::string('db_host')->setOptional(null), ]); // 'db_host' devient requis uniquement si 'has_database' est true $resolver->addRequiredIf('db_host', 'has_database', true);
Obsolescence (Deprecation)
Vous pouvez marquer une option comme obsolète. Une erreur E_USER_DEPRECATED sera déclenchée si l'option est utilisée.
Option::string('old_option')->deprecate('Utilisez "new_option" à la place.');
Contraintes Supplémentaires
La bibliothèque fournit des aides pour des contraintes courantes comme min et max. Elles fonctionnent pour les chaînes (longueur), les nombres (valeur) et les tableaux (nombre d'éléments).
Option::string('username')->min(3)->max(20); Option::int('age')->min(18); Option::array('tags')->max(5);
Validateurs Multiples
Vous pouvez enchaîner plusieurs validateurs. Tous doivent être valides.
Option::string('code') ->validator(fn($v) => str_starts_with($v, 'A')) ->validator(fn($v) => str_ends_with($v, 'Z'));
Licence
Ce projet est sous licence MIT. Voir le fichier LICENSE pour plus de détails.