@@ -56,6 +56,11 @@ final public static function make(mixed ...$params): static
5656 );
5757 }
5858
59+ // Handle named parameters if provided
60+ if (self ::hasNamedParameters ($ params )) {
61+ $ params = self ::mapNamedToPositional ($ constructor , $ params );
62+ }
63+
5964 // Validate parameters against constructor signature
6065 // array_values ensures we have a proper indexed array
6166 self ::validateConstructorParameters ($ constructor , array_values ($ params ));
@@ -211,6 +216,74 @@ private static function validateUnionType(mixed $value, ReflectionUnionType $uni
211216 return false ;
212217 }
213218
219+ /**
220+ * Check if parameters include named parameters.
221+ *
222+ * @param array<int|string, mixed> $params
223+ * @return bool
224+ */
225+ private static function hasNamedParameters (array $ params ): bool
226+ {
227+ if (empty ($ params )) {
228+ return false ;
229+ }
230+
231+ // Named parameters have string keys
232+ // Positional parameters have sequential integer keys [0, 1, 2, ...]
233+ return array_keys ($ params ) !== range (0 , count ($ params ) - 1 );
234+ }
235+
236+ /**
237+ * Map named parameters to positional parameters based on constructor signature.
238+ *
239+ * Supports three scenarios:
240+ * 1. Pure named parameters: make(value: 'test')
241+ * 2. Pure positional parameters: make('test')
242+ * 3. Mixed parameters: make(1, name: 'test', description: 'desc')
243+ *
244+ * @param ReflectionMethod $constructor
245+ * @param array<int|string, mixed> $params
246+ * @return array<int, mixed>
247+ * @throws InvalidArgumentException When required named parameter is missing
248+ */
249+ private static function mapNamedToPositional (
250+ ReflectionMethod $ constructor ,
251+ array $ params
252+ ): array {
253+ $ positional = [];
254+ $ constructorParams = $ constructor ->getParameters ();
255+
256+ foreach ($ constructorParams as $ index => $ param ) {
257+ $ name = $ param ->getName ();
258+
259+ // Check if parameter was provided positionally (by index)
260+ if (array_key_exists ($ index , $ params )) {
261+ $ positional [$ index ] = $ params [$ index ];
262+ }
263+ // Check if parameter was provided by name
264+ elseif (array_key_exists ($ name , $ params )) {
265+ $ positional [$ index ] = $ params [$ name ];
266+ }
267+ // Check if parameter has a default value
268+ elseif ($ param ->isDefaultValueAvailable ()) {
269+ $ positional [$ index ] = $ param ->getDefaultValue ();
270+ }
271+ // Check if parameter is required
272+ elseif (!$ param ->isOptional ()) {
273+ throw new InvalidArgumentException (
274+ sprintf (
275+ '%s::make() missing required parameter: %s ' ,
276+ basename (str_replace ('\\' , '/ ' , static ::class)),
277+ $ name
278+ )
279+ );
280+ }
281+ // else: optional parameter without default (e.g., nullable), will be handled by PHP
282+ }
283+
284+ return $ positional ;
285+ }
286+
214287 /**
215288 * Determine if invariants should be checked automatically after construction.
216289 *
0 commit comments