@@ -38,49 +38,91 @@ final class Block implements Iterator, ArrayAccess, Countable
3838 /** @var array<int|string, mixed> */
3939 private array $ data ;
4040
41- private const MISSING_KEY_SILENT = 0 ;
42- private const MISSING_KEY_WARNING = 1 ;
41+ /**
42+ * Missing key handling mode: return default value silently.
43+ */
44+ private const MISSING_KEY_SILENT = 0 ;
45+
46+ /**
47+ * Missing key handling mode: emit a warning and continue execution.
48+ */
49+ private const MISSING_KEY_WARNING = 1 ;
50+
51+ /**
52+ * Missing key handling mode: throw an exception.
53+ */
4354 private const MISSING_KEY_EXCEPTION = 2 ;
4455
56+ /**
57+ * Current missing key handling mode.
58+ *
59+ * One of:
60+ * - self::MISSING_KEY_SILENT
61+ * - self::MISSING_KEY_WARNING
62+ * - self::MISSING_KEY_EXCEPTION
63+ */
4564 private int $ missingKeyMode = self ::MISSING_KEY_SILENT ;
4665
47- /** @var class-string<\Throwable>|null */
66+
67+ /** @var class-string<\Throwable>|null Exception class to throw on missing key */
4868 private ?string $ missingKeyExceptionClass = null ;
69+ /** @var string|null Optional hint appended to the exception message */
70+ private ?string $ missingKeyExceptionHint = null ;
4971
5072 /** @param array<int|string, mixed> $data */
5173 public function __construct (array $ data = [], private bool $ iteratorReturnsBlock = true )
5274 {
5375 $ this ->data = $ data ;
5476 }
5577
78+ /**
79+ * Use silent mode when accessing missing keys (return default value).
80+ */
5681 public function silentOnMissingKey (): self
5782 {
5883 $ this ->missingKeyMode = self ::MISSING_KEY_SILENT ;
84+ $ this ->missingKeyExceptionClass = null ;
85+ $ this ->missingKeyExceptionHint = null ;
5986 return $ this ;
6087 }
6188
62- public function warnOnMissingKey (bool $ enabled = true ): self
89+ /**
90+ * Emit a warning when accessing a missing key.
91+ */
92+ public function warnOnMissingKey (): self
6393 {
64- $ this ->missingKeyMode = $ enabled
65- ? self ::MISSING_KEY_WARNING
66- : self ::MISSING_KEY_SILENT ;
94+ $ this ->missingKeyMode = self ::MISSING_KEY_WARNING ;
6795
6896 return $ this ;
6997 }
7098
7199 /**
100+ * Configure the Block object to throw an exception when accessing a missing key.
101+ *
102+ * When enabled, any access to a non-existing key will throw an exception of the
103+ * given class instead of returning the default value.
104+ *
105+ * An optional hint can be provided to add extra context to the exception message.
72106 *
73- * @param class-string<\Throwable> $exceptionClass
107+ * @param class-string<\Throwable> $exceptionClass Exception class to throw (must extend Throwable)
108+ * @param string|null $hint Optional additional context appended to the exception message
109+ *
110+ * @return self Returns the current instance for method chaining.
111+ *
112+ * @throws \InvalidArgumentException If the given class does not extend Throwable
74113 */
75- public function throwOnMissingKey (string $ exceptionClass = \OutOfBoundsException::class): self
76- {
114+ public function throwOnMissingKey (
115+ string $ exceptionClass = \OutOfBoundsException::class,
116+ ?string $ hint = null ,
117+ ): self {
77118 /** @phpstan-ignore function.alreadyNarrowedType, booleanAnd.alwaysFalse */
78119 if (!is_subclass_of ($ exceptionClass , \Throwable::class) && $ exceptionClass !== \Throwable::class) {
79120 throw new \InvalidArgumentException ("Exception class must extend Throwable " );
80121 }
81122
82123 $ this ->missingKeyMode = self ::MISSING_KEY_EXCEPTION ;
83124 $ this ->missingKeyExceptionClass = $ exceptionClass ;
125+ $ this ->missingKeyExceptionHint = $ hint ;
84126
85127 return $ this ;
86128 }
@@ -94,7 +136,12 @@ private function handleMissingKey(int|string $key, mixed $defaultValue): mixed
94136
95137 case self ::MISSING_KEY_EXCEPTION :
96138 $ class = $ this ->missingKeyExceptionClass ?? \OutOfBoundsException::class;
97- throw new $ class ("Undefined array key: " . $ key );
139+ $ message = "Undefined array key: " . $ key ;
140+ if ($ this ->missingKeyExceptionHint ) {
141+ $ message = $ message . " ( " . $ this ->missingKeyExceptionHint . ") " ;
142+ }
143+
144+ throw new $ class ($ message );
98145
99146 case self ::MISSING_KEY_SILENT :
100147 default :
0 commit comments