{"id":23289781,"url":"https://github.com/cmatosbc/desired-patterns","last_synced_at":"2026-02-28T22:31:51.232Z","repository":{"id":268646007,"uuid":"905037022","full_name":"cmatosbc/desired-patterns","owner":"cmatosbc","description":"Desirable, practical, modern and sexy design patterns for PHP 8.2 onwards that can actually be used, not just seen.","archived":false,"fork":false,"pushed_at":"2025-02-24T14:49:16.000Z","size":119,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-03T14:11:45.769Z","etag":null,"topics":["chain-of-responsibility-pattern","command-pattern","design-patterns","multiton-pattern","php-design-patterns","php-examples","php-patterns","php8","pipeline-pattern","registry-pattern","service-locator-pattern","singleton-pattern","specification-pattern","state-pattern"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cmatosbc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-12-18T03:15:33.000Z","updated_at":"2025-02-24T14:49:20.000Z","dependencies_parsed_at":"2024-12-18T04:20:23.970Z","dependency_job_id":"a70023bb-c3a0-4b17-91f7-e47daf39d984","html_url":"https://github.com/cmatosbc/desired-patterns","commit_stats":{"total_commits":24,"total_committers":1,"mean_commits":24.0,"dds":0.0,"last_synced_commit":"6068ebb1e948ede615db791060261bf4fea528bc"},"previous_names":["cmatosbc/desired-patterns"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/cmatosbc/desired-patterns","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmatosbc%2Fdesired-patterns","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmatosbc%2Fdesired-patterns/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmatosbc%2Fdesired-patterns/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmatosbc%2Fdesired-patterns/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cmatosbc","download_url":"https://codeload.github.com/cmatosbc/desired-patterns/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmatosbc%2Fdesired-patterns/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29953287,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-28T18:42:55.706Z","status":"ssl_error","status_checked_at":"2026-02-28T18:42:48.811Z","response_time":90,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chain-of-responsibility-pattern","command-pattern","design-patterns","multiton-pattern","php-design-patterns","php-examples","php-patterns","php8","pipeline-pattern","registry-pattern","service-locator-pattern","singleton-pattern","specification-pattern","state-pattern"],"created_at":"2024-12-20T04:18:08.045Z","updated_at":"2026-02-28T22:31:51.184Z","avatar_url":"https://github.com/cmatosbc.png","language":"PHP","readme":"# Modern PHP Design Patterns\n\n[![PHP Lint](https://github.com/cmatosbc/desired-patterns/actions/workflows/lint.yml/badge.svg)](https://github.com/cmatosbc/desired-patterns/actions/workflows/lint.yml) [![PHPUnit Tests](https://github.com/cmatosbc/desired-patterns/actions/workflows/phpunit.yml/badge.svg)](https://github.com/cmatosbc/desired-patterns/actions/workflows/phpunit.yml) [![PHP Composer](https://github.com/cmatosbc/desired-patterns/actions/workflows/composer.yml/badge.svg)](https://github.com/cmatosbc/desired-patterns/actions/workflows/composer.yml) ![Code Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/cmatosbc/664fd72a90f996481f161d1d3a2f7285/raw/coverage.json)\n\nA collection of modern PHP design patterns implemented using PHP 8.2+ features. Sexier than older implementations and more readable than ever.\n\n## Requirements\n\n- PHP 8.2 or higher\n- Composer\n\n## Installation\n\n```bash\ncomposer require cmatosbc/desired-patterns\n```\n\n## Patterns Implemented\n\nQuick Links:\n- [1. Singleton Pattern](#1-singleton-pattern)\n- [2. Multiton Pattern](#2-multiton-pattern)\n- [3. Command Pattern](#3-command-pattern)\n- [4. Chain of Responsibility Pattern](#4-chain-of-responsibility-pattern)\n- [5. Registry Pattern](#5-registry-pattern)\n- [6. Service Locator Pattern](#6-service-locator-pattern)\n- [7. Specification Pattern](#7-specification-pattern)\n- [8. Strategy Pattern](#8-strategy-pattern)\n- [9. State Pattern](#9-state-pattern)\n- [10. Pipeline Pattern](#10-pipeline-pattern)\n- [11. Object Pool Pattern](#11-object-pool-pattern)\n- [12. Null Object Pattern](#12-null-object-pattern)\n\n### 1. Singleton Pattern\nThe Singleton pattern ensures a class has only one instance and provides a global point of access to it. Our implementation uses a trait to make it reusable.\n\n```php\nuse DesiredPatterns\\Traits\\Singleton;\n\nclass Database\n{\n    use Singleton;\n\n    private function __construct()\n    {\n        // Initialize database connection\n    }\n\n    public function query(string $sql): array\n    {\n        // Execute query\n    }\n}\n\n// Usage\n$db = Database::getInstance();\n```\n\n### 2. Multiton Pattern\nThe Multiton pattern is similar to Singleton but maintains a map of named instances. This is useful when you need multiple named instances of a class.\n\n```php\nuse DesiredPatterns\\Traits\\Multiton;\n\nclass Configuration\n{\n    use Multiton;\n\n    private string $environment;\n\n    private function __construct(string $environment)\n    {\n        $this-\u003eenvironment = $environment;\n    }\n\n    public function getEnvironment(): string\n    {\n        return $this-\u003eenvironment;\n    }\n}\n\n// Usage\n$devConfig = Configuration::getInstance('development');\n$prodConfig = Configuration::getInstance('production');\n\n// Check if instance exists\nif (Configuration::hasInstance('testing')) {\n    // ...\n}\n```\n\n### 3. Command Pattern\nThe Command pattern encapsulates a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.\n\n```php\nuse DesiredPatterns\\Commands\\AbstractCommand;\nuse DesiredPatterns\\Commands\\AbstractCommandHandler;\n\n// Command\nclass CreateUserCommand extends AbstractCommand\n{\n    public function __construct(\n        public readonly string $name,\n        public readonly string $email\n    ) {}\n}\n\n// Handler\nclass CreateUserHandler extends AbstractCommandHandler\n{\n    public function handle(CreateUserCommand $command): void\n    {\n        // Create user logic here\n    }\n\n    public function supports(object $command): bool\n    {\n        return $command instanceof CreateUserCommand;\n    }\n}\n\n// Usage\n$command = new CreateUserCommand('John Doe', 'john@example.com');\n$handler = new CreateUserHandler();\n$handler-\u003ehandle($command);\n```\n\n### 4. Chain of Responsibility Pattern\nThe Chain of Responsibility pattern lets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.\n\n```php\nuse DesiredPatterns\\Chain\\AbstractHandler;\n\n// Create concrete handlers\nclass PayPalHandler extends AbstractHandler\n{\n    public function handle($request)\n    {\n        if ($request['type'] === 'paypal') {\n            return [\n                'status' =\u003e 'success',\n                'message' =\u003e 'Payment processed via PayPal'\n            ];\n        }\n        \n        return parent::handle($request);\n    }\n}\n\nclass CreditCardHandler extends AbstractHandler\n{\n    public function handle($request)\n    {\n        if ($request['type'] === 'credit_card') {\n            return [\n                'status' =\u003e 'success',\n                'message' =\u003e 'Payment processed via credit card'\n            ];\n        }\n        \n        return parent::handle($request);\n    }\n}\n\n// Usage\n$paypalHandler = new PayPalHandler();\n$creditCardHandler = new CreditCardHandler();\n\n// Build the chain\n$paypalHandler-\u003esetNext($creditCardHandler);\n\n// Process payment\n$result = $paypalHandler-\u003ehandle([\n    'type' =\u003e 'credit_card',\n    'amount' =\u003e 100.00\n]);\n```\n\n### 5. Registry Pattern\nThe Registry pattern provides a global point of access to objects or services throughout an application.\n\n```php\nuse DesiredPatterns\\Registry\\Registry;\n\n// Store a value\nRegistry::set('config.database', [\n    'host' =\u003e 'localhost',\n    'name' =\u003e 'myapp'\n]);\n\n// Retrieve a value\n$dbConfig = Registry::get('config.database');\n\n// Check if key exists\nif (Registry::has('config.database')) {\n    // ...\n}\n\n// Remove a key\nRegistry::remove('config.database');\n\n// Get all keys\n$keys = Registry::keys();\n```\n\n### 6. Service Locator Pattern\nThe Service Locator pattern is a design pattern used to encapsulate the processes involved in obtaining a service with a strong abstraction layer.\n\n```php\nuse DesiredPatterns\\ServiceLocator\\ServiceLocator;\n\nclass DatabaseService\n{\n    public function connect(): void\n    {\n        // Connection logic\n    }\n}\n\n// Create a service locator\n$locator = new ServiceLocator();\n\n// Register a service\n$locator-\u003eregister('database', fn() =\u003e new DatabaseService());\n\n// Resolve the service\n$db = $locator-\u003eresolve('database');\n\n// Check if service exists\nif ($locator-\u003ehas('database')) {\n    // ...\n}\n\n// Extend an existing service\n$locator-\u003eextend('database', function($service) {\n    // Modify or decorate the service\n    return $service;\n});\n```\n\n### 7. Specification Pattern\nThe Specification pattern is used to create business rules that can be combined using boolean logic.\n\n```php\nuse DesiredPatterns\\Specifications\\AbstractSpecification;\nuse DesiredPatterns\\Specifications\\Composite\\{AndSpecification, OrSpecification, NotSpecification};\n\n// Create specifications\nclass AgeSpecification extends AbstractSpecification\n{\n    public function __construct(private int $minAge) {}\n\n    public function isSatisfiedBy(mixed $candidate): bool\n    {\n        return $candidate-\u003eage \u003e= $this-\u003eminAge;\n    }\n}\n\nclass VerifiedSpecification extends AbstractSpecification\n{\n    public function isSatisfiedBy(mixed $candidate): bool\n    {\n        return $candidate-\u003eisVerified;\n    }\n}\n\n// Usage\n$isAdult = new AgeSpecification(18);\n$isVerified = new VerifiedSpecification();\n\n// Combine specifications\n$canAccessContent = $isAdult-\u003eand($isVerified);\n\n// Check if specifications are met\n$user = new stdClass();\n$user-\u003eage = 25;\n$user-\u003eisVerified = true;\n\nif ($canAccessContent-\u003eisSatisfiedBy($user)) {\n    // Allow access\n}\n```\n\n### 8. Strategy Pattern\n\nThe Strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. It lets the algorithm vary independently from clients that use it.\n\n### Real-World Examples\n\n1. **Payment Processing**\n   - Different payment methods (Credit Card, PayPal, Cryptocurrency)\n   - Each payment method has its own validation and processing logic\n   - System can switch between payment strategies based on user selection\n\n2. **Data Export**\n   - Multiple export formats (CSV, JSON, XML, PDF)\n   - Each format has specific formatting requirements\n   - Choose export strategy based on user preference or file type\n\n3. **Shipping Calculation**\n   - Various shipping providers (FedEx, UPS, DHL)\n   - Each provider has unique rate calculation algorithms\n   - Select provider based on destination, weight, or cost\n\n### Complete Example\n\n```php\n\nnamespace Examples\\Strategy\\Payment;\n\nuse DesiredPatterns\\Strategy\\AbstractStrategy;\nuse DesiredPatterns\\Traits\\ConfigurableStrategyTrait;\n\n/**\n * Credit Card Payment Strategy\n */\nclass CreditCardStrategy extends AbstractStrategy\n{\n    use ConfigurableStrategyTrait;\n\n    protected array $requiredOptions = ['api_key'];\n\n    public function supports(array $data): bool\n    {\n        return isset($data['payment_method']) \n            \u0026\u0026 $data['payment_method'] === 'credit_card';\n    }\n\n    public function validate(array $data): bool\n    {\n        return isset($data['card_number'])\n            \u0026\u0026 isset($data['expiry'])\n            \u0026\u0026 isset($data['cvv']);\n    }\n\n    public function execute(array $data): array\n    {\n        // Process credit card payment\n        return [\n            'status' =\u003e 'success',\n            'transaction_id' =\u003e uniqid('cc_'),\n            'method' =\u003e 'credit_card',\n            'amount' =\u003e $data['amount']\n        ];\n    }\n}\n\n/**\n * PayPal Payment Strategy\n */\nclass PayPalStrategy extends AbstractStrategy\n{\n    use ConfigurableStrategyTrait;\n\n    protected array $requiredOptions = ['client_id', 'client_secret'];\n\n    public function supports(array $data): bool\n    {\n        return isset($data['payment_method']) \n            \u0026\u0026 $data['payment_method'] === 'paypal';\n    }\n\n    public function validate(array $data): bool\n    {\n        return isset($data['paypal_email']) \n            \u0026\u0026 isset($data['amount']);\n    }\n\n    public function execute(array $data): array\n    {\n        // Process PayPal payment\n        return [\n            'status' =\u003e 'success',\n            'transaction_id' =\u003e uniqid('pp_'),\n            'method' =\u003e 'paypal',\n            'amount' =\u003e $data['amount']\n        ];\n    }\n}\n\n/**\n * Cryptocurrency Payment Strategy\n */\nclass CryptoStrategy extends AbstractStrategy\n{\n    use ConfigurableStrategyTrait;\n\n    protected array $requiredOptions = ['wallet_address'];\n\n    public function supports(array $data): bool\n    {\n        return isset($data['payment_method']) \n            \u0026\u0026 $data['payment_method'] === 'crypto';\n    }\n\n    public function validate(array $data): bool\n    {\n        return isset($data['crypto_address']) \n            \u0026\u0026 isset($data['crypto_currency']);\n    }\n\n    public function execute(array $data): array\n    {\n        // Process crypto payment\n        return [\n            'status' =\u003e 'success',\n            'transaction_id' =\u003e uniqid('crypto_'),\n            'method' =\u003e 'crypto',\n            'amount' =\u003e $data['amount'],\n            'currency' =\u003e $data['crypto_currency']\n        ];\n    }\n}\n\n// Usage Example\n$context = new StrategyContext();\n\n// Configure payment strategies\n$context-\u003eaddStrategy(\n    new CreditCardStrategy(),\n    ['api_key' =\u003e 'sk_test_123']\n)\n-\u003eaddStrategy(\n    new PayPalStrategy(),\n    [\n        'client_id' =\u003e 'client_123',\n        'client_secret' =\u003e 'secret_456'\n    ]\n)\n-\u003eaddStrategy(\n    new CryptoStrategy(),\n    ['wallet_address' =\u003e '0x123...']\n);\n\n// Process a credit card payment\n$ccPayment = $context-\u003eexecuteStrategy([\n    'payment_method' =\u003e 'credit_card',\n    'amount' =\u003e 99.99,\n    'card_number' =\u003e '4242424242424242',\n    'expiry' =\u003e '12/25',\n    'cvv' =\u003e '123'\n]);\n\n// Process a PayPal payment\n$ppPayment = $context-\u003eexecuteStrategy([\n    'payment_method' =\u003e 'paypal',\n    'amount' =\u003e 149.99,\n    'paypal_email' =\u003e 'customer@example.com'\n]);\n\n// Process a crypto payment\n$cryptoPayment = $context-\u003eexecuteStrategy([\n    'payment_method' =\u003e 'crypto',\n    'amount' =\u003e 199.99,\n    'crypto_address' =\u003e '0x456...',\n    'crypto_currency' =\u003e 'ETH'\n]);\n```\n\n### 9. State Pattern\nThe State pattern allows an object to alter its behavior when its internal state changes. The object will appear to change its class. Our implementation provides a flexible and type-safe way to handle state transitions with context validation.\n\n```php\nuse DesiredPatterns\\State\\StateMachineTrait;\nuse DesiredPatterns\\State\\AbstractState;\n\n// Define your states\nclass PendingState extends AbstractState\n{\n    public function getName(): string\n    {\n        return 'pending';\n    }\n\n    protected array $allowedTransitions = ['processing', 'cancelled'];\n    \n    protected array $validationRules = [\n        'order_id' =\u003e 'required',\n        'amount' =\u003e 'type:double'\n    ];\n\n    public function handle(array $context): array\n    {\n        return [\n            'status' =\u003e 'pending',\n            'message' =\u003e 'Order is being validated',\n            'order_id' =\u003e $context['order_id']\n        ];\n    }\n}\n\n// Create your state machine\nclass Order\n{\n    use StateMachineTrait;\n\n    public function __construct(string $orderId)\n    {\n        // Initialize states\n        $this-\u003eaddState(new PendingState(), true)\n            -\u003eaddState(new ProcessingState())\n            -\u003eaddState(new ShippedState());\n\n        // Set initial context\n        $this-\u003eupdateContext([\n            'order_id' =\u003e $orderId,\n            'created_at' =\u003e date('Y-m-d H:i:s')\n        ]);\n    }\n\n    public function process(array $paymentDetails): array\n    {\n        $this-\u003etransitionTo('processing', $paymentDetails);\n        return $this-\u003egetCurrentState()-\u003ehandle($this-\u003egetContext());\n    }\n}\n\n// Usage\n$order = new Order('ORD-123');\n\ntry {\n    $result = $order-\u003eprocess([\n        'payment_id' =\u003e 'PAY-456',\n        'amount' =\u003e 99.99\n    ]);\n    echo $result['message']; // \"Payment verified, preparing shipment\"\n} catch (StateException $e) {\n    echo \"Error: \" . $e-\u003egetMessage();\n}\n```\n\n#### Real-World Example: Order Processing System\n\nThe State pattern is perfect for managing complex workflows like order processing. Each state encapsulates its own rules and behaviors:\n\n1. **States**:\n   - `PendingState`: Initial state, validates order details\n   - `ProcessingState`: Handles payment verification\n   - `ShippedState`: Manages shipping details\n   - `DeliveredState`: Handles delivery confirmation\n   - `CancelledState`: Manages order cancellation\n\n2. **Features**:\n   - Context validation per state\n   - Type-safe state transitions\n   - State history tracking\n   - Fluent interface for state machine setup\n\n3. **Benefits**:\n   - Clean separation of concerns\n   - Easy to add new states\n   - Type-safe state transitions\n   - Automatic context validation\n   - Comprehensive state history\n\n4. **Use Cases**:\n   - Order Processing Systems\n   - Document Workflow Management\n   - Game State Management\n   - Payment Processing\n   - Task Management Systems\n\n### 10. Pipeline Pattern\n\nThe Pipeline pattern allows you to process data through a series of operations, where each operation takes input from the previous operation and produces output for the next one. This pattern is particularly useful for data transformation, validation, and processing workflows.\n\n#### Features\n- Fluent interface for operation chaining\n- Built-in error handling\n- Input validation\n- Type-safe operations with PHP 8.2+ generics\n- Side effect management\n- Conditional processing\n- Operation composition\n\n#### Basic Usage\n\n```php\nuse DesiredPatterns\\Pipeline\\Pipeline;\n\n// Basic pipeline\n$result = Pipeline::of(5)\n    -\u003epipe(fn($x) =\u003e $x * 2)    // 10\n    -\u003epipe(fn($x) =\u003e $x + 1)    // 11\n    -\u003eget();                     // Returns: 11\n\n// Pipeline with error handling\n$result = Pipeline::of($value)\n    -\u003etry(\n        fn($x) =\u003e processData($x),\n        fn(\\Throwable $e) =\u003e handleError($e)\n    )\n    -\u003eget();\n\n// Pipeline with validation\n$result = Pipeline::of($data)\n    -\u003ewhen(\n        fn($x) =\u003e $x \u003e 0,\n        fn($x) =\u003e sqrt($x)\n    )\n    -\u003eget();\n```\n\n#### Advanced Usage with PipelineBuilder\n\nThe PipelineBuilder provides a more structured way to create complex pipelines with validation and error handling:\n\n```php\nuse DesiredPatterns\\Pipeline\\PipelineBuilder;\n\n$builder = new PipelineBuilder();\n$result = $builder\n    -\u003ewithValidation(fn($x) =\u003e $x \u003e 0, 'Value must be positive')\n    -\u003ewithValidation(fn($x) =\u003e $x \u003c 100, 'Value must be less than 100')\n    -\u003ewithErrorHandling(fn(\\Throwable $e) =\u003e handleValidationError($e))\n    -\u003eadd(fn($x) =\u003e $x * 2)\n    -\u003eadd(fn($x) =\u003e \"Result: $x\")\n    -\u003ebuild(50)\n    -\u003eget();\n```\n\n#### Real-World Example: Data Processing Pipeline\n\nHere's a real-world example of using the Pipeline pattern for processing user data:\n\n```php\nclass UserDataProcessor\n{\n    private PipelineBuilder $pipeline;\n\n    public function __construct()\n    {\n        $this-\u003epipeline = new PipelineBuilder();\n        $this-\u003epipeline\n            -\u003ewithValidation(\n                fn($data) =\u003e isset($data['email']),\n                'Email is required'\n            )\n            -\u003ewithValidation(\n                fn($data) =\u003e filter_var($data['email'], FILTER_VALIDATE_EMAIL),\n                'Invalid email format'\n            )\n            -\u003ewithErrorHandling(fn(\\Throwable $e) =\u003e [\n                'success' =\u003e false,\n                'error' =\u003e $e-\u003egetMessage()\n            ])\n            -\u003eadd(function($data) {\n                // Normalize email\n                $data['email'] = strtolower($data['email']);\n                return $data;\n            })\n            -\u003eadd(function($data) {\n                // Hash password if present\n                if (isset($data['password'])) {\n                    $data['password'] = password_hash(\n                        $data['password'],\n                        PASSWORD_DEFAULT\n                    );\n                }\n                return $data;\n            })\n            -\u003eadd(function($data) {\n                // Add metadata\n                $data['created_at'] = new DateTime();\n                $data['status'] = 'active';\n                return $data;\n            });\n    }\n\n    public function process(array $userData): array\n    {\n        return $this-\u003epipeline\n            -\u003ebuild($userData)\n            -\u003eget();\n    }\n}\n\n// Usage\n$processor = new UserDataProcessor();\n\n// Successful case\n$result = $processor-\u003eprocess([\n    'email' =\u003e 'user@example.com',\n    'password' =\u003e 'secret123'\n]);\n// Returns: [\n//     'email' =\u003e 'user@example.com',\n//     'password' =\u003e '$2y$10$...',\n//     'created_at' =\u003e DateTime,\n//     'status' =\u003e 'active'\n// ]\n\n// Error case\n$result = $processor-\u003eprocess([\n    'email' =\u003e 'invalid-email'\n]);\n// Returns: [\n//     'success' =\u003e false,\n//     'error' =\u003e 'Invalid email format'\n// ]\n```\n\n#### Benefits\n1. **Separation of Concerns**: Each operation in the pipeline has a single responsibility.\n2. **Maintainability**: Easy to add, remove, or modify processing steps without affecting other parts.\n3. **Reusability**: Pipeline operations can be reused across different contexts.\n4. **Error Handling**: Built-in error handling makes it easy to manage failures.\n5. **Validation**: Input validation can be added at any point in the pipeline.\n6. **Type Safety**: PHP 8.2+ generics provide type safety throughout the pipeline.\n7. **Testability**: Each operation can be tested in isolation.\n\n#### Use Cases\n- Data transformation and normalization\n- Form validation and processing\n- API request/response handling\n- Image processing workflows\n- ETL (Extract, Transform, Load) operations\n- Document processing pipelines\n- Multi-step validation processes\n\n### 11. Object Pool Pattern\nThe Object Pool pattern manages a fixed set of reusable objects that are expensive to create or consume significant resources. Our implementation uses PHP 8.2 features for type-safe object management and automatic cleanup.\n\n```php\nuse DesiredPatterns\\Contracts\\PoolableInterface;\nuse DesiredPatterns\\Pool\\ObjectPool;\nuse DesiredPatterns\\Pool\\PoolFactory;\n\n// Define a poolable resource\nclass DatabaseConnection implements PoolableInterface\n{\n    private ?PDO $connection = null;\n    \n    public function __construct(\n        private readonly string $dsn,\n        private readonly string $username,\n        private readonly string $password\n    ) {}\n    \n    public function reset(): void\n    {\n        if ($this-\u003econnection) {\n            $this-\u003econnection-\u003esetAttribute(PDO::ATTR_AUTOCOMMIT, true);\n        }\n    }\n    \n    public function validate(): bool\n    {\n        try {\n            $this-\u003econnection?-\u003equery('SELECT 1');\n            return true;\n        } catch (PDOException) {\n            $this-\u003econnection = null;\n            return false;\n        }\n    }\n}\n\n// Use the pool\n$pool = PoolFactory::getPool(\n    'database',\n    DatabaseConnection::class,\n    [\n        'min_instances' =\u003e 2,\n        'max_instances' =\u003e 10,\n        'constructor_args' =\u003e [\n            'mysql:host=localhost;dbname=test',\n            'username',\n            'password'\n        ]\n    ]\n);\n\n// Acquire and use a connection\n$connection = $pool-\u003eacquire();\ntry {\n    // Use the connection\n} finally {\n    $pool-\u003erelease($connection);\n}\n```\n\n1. **Key Features**:\n   - Type-safe resource management\n   - Automatic resource cleanup using WeakMap\n   - Configurable pool sizes\n   - Resource validation and reset\n   - Usage statistics tracking\n\n2. **Use Cases**:\n   - Database connection pooling\n   - File handle management\n   - Network socket management\n   - Thread/Process pooling\n   - Memory-intensive object reuse\n\n### 12. Null Object Pattern\nThe Null Object pattern provides an object with neutral (\"null\") behavior as an alternative to null references. Our implementation uses PHP 8.2 features for type-safe null handling and interface contracts.\n\n```php\nuse DesiredPatterns\\NullObject\\NullableInterface;\nuse DesiredPatterns\\NullObject\\AbstractNullObject;\n\n// Define the interface\ninterface LoggerInterface extends NullableInterface\n{\n    public function log(string $level, string $message, array $context = []): void;\n    public function getLogs(): array;\n}\n\n// Real implementation\nclass FileLogger implements LoggerInterface\n{\n    public function __construct(\n        private readonly string $logFile\n    ) {}\n    \n    public function log(string $level, string $message, array $context = []): void\n    {\n        file_put_contents(\n            $this-\u003elogFile,\n            \"[$level] $message \" . json_encode($context) . PHP_EOL,\n            FILE_APPEND\n        );\n    }\n    \n    public function getLogs(): array\n    {\n        return file($this-\u003elogFile);\n    }\n    \n    public function isNull(): bool\n    {\n        return false;\n    }\n}\n\n// Null implementation\nclass NullLogger extends AbstractNullObject implements LoggerInterface\n{\n    public function log(string $level, string $message, array $context = []): void\n    {\n        // Do nothing\n    }\n    \n    public function getLogs(): array\n    {\n        return [];\n    }\n}\n\n// Usage\nclass UserService\n{\n    public function __construct(\n        private readonly LoggerInterface $logger = new NullLogger()\n    ) {}\n    \n    public function createUser(string $username): void\n    {\n        // Create user...\n        $this-\u003elogger-\u003elog('info', 'User created', ['username' =\u003e $username]);\n    }\n}\n```\n\n1. **Key Features**:\n   - Type-safe null object implementation\n   - Interface-based contracts\n   - Abstract base class for null objects\n   - Explicit null checking through interface\n   - Zero-impact performance for null operations\n\n2. **Use Cases**:\n   - Optional service dependencies\n   - Testing and development environments\n   - Feature toggles and graceful degradation\n   - Default behavior implementation\n   - Error handling and logging\n\n## Testing\n\nRun the test suite using PHPUnit :\n\n```bash\nvendor/bin/phpunit\n```\n\nOr run it updating the coverage report:\n\n```bash\nvendor/bin/phpunit --coverage-html coverage\n```\n\n## Contributing\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis library is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcmatosbc%2Fdesired-patterns","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcmatosbc%2Fdesired-patterns","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcmatosbc%2Fdesired-patterns/lists"}