From 6985ff305a8448a8225d373aa9172090d275b3b1 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Mon, 14 Sep 2026 13:26:03 +0200 Subject: [PATCH 1/7] Count constant array finite types before building them ConstantArrayType::getFiniteTypes() forked a builder per optional key and only noticed after each key that the partial set had grown past CALCULATE_SCALARS_LIMIT, so a shape with many optional keys paid hundreds of builder clones per call for an empty result. Every caller that asks a large shape (the remove() finite-set difference, the ternary-arm and re-assignment checks in AssignHandler) hit this. Multiply the per-key counts first and only build when the product stays within the limit; the result is unchanged. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01GvDxWpzXzticTTm5eLCsb2 --- src/Type/Constant/ConstantArrayType.php | 23 +- .../data/finite-types-optional-keys-count.php | 3021 +++++++++++++++++ 2 files changed, 3038 insertions(+), 6 deletions(-) create mode 100644 tests/bench/data/finite-types-optional-keys-count.php diff --git a/src/Type/Constant/ConstantArrayType.php b/src/Type/Constant/ConstantArrayType.php index 2f3471bbd67..9257a650c6e 100644 --- a/src/Type/Constant/ConstantArrayType.php +++ b/src/Type/Constant/ConstantArrayType.php @@ -3606,15 +3606,29 @@ public function getFiniteTypes(): array // Build finite array types incrementally, processing one key at a time. // For optional keys, fork each partial result into with/without variants. // This avoids generating 2^N ConstantArrayType objects via getAllArrays(). - /** @var list $partials */ - $partials = [ConstantArrayTypeBuilder::createEmpty()]; - + // Count first: a shape with many optional keys overflows the limit after a + // handful of keys, and building the partial arrays up to that point costs + // hundreds of builder clones per call for a result that is thrown away. + $finiteValueTypesPerKey = []; + $count = 1; foreach ($this->keyTypes as $i => $keyType) { $finiteValueTypes = $this->valueTypes[$i]->getFiniteTypes(); if ($finiteValueTypes === []) { return []; } + $finiteValueTypesPerKey[$i] = $finiteValueTypes; + $count *= count($finiteValueTypes) + ($this->isOptionalKey($i) ? 1 : 0); + if ($count > $limit) { + return []; + } + } + + /** @var list $partials */ + $partials = [ConstantArrayTypeBuilder::createEmpty()]; + + foreach ($this->keyTypes as $i => $keyType) { + $finiteValueTypes = $finiteValueTypesPerKey[$i]; $isOptional = $this->isOptionalKey($i); $newPartials = []; @@ -3630,9 +3644,6 @@ public function getFiniteTypes(): array } $partials = $newPartials; - if (count($partials) > $limit) { - return []; - } } $finiteTypes = []; diff --git a/tests/bench/data/finite-types-optional-keys-count.php b/tests/bench/data/finite-types-optional-keys-count.php new file mode 100644 index 00000000000..f5a49ff1ad9 --- /dev/null +++ b/tests/bench/data/finite-types-optional-keys-count.php @@ -0,0 +1,3021 @@ + Date: Mon, 14 Sep 2026 13:35:42 +0200 Subject: [PATCH 2/7] Remove a union of enum cases from a sealed hierarchy in one subtraction TypeCombinator::remove() removes a union from a sealed hierarchy at once only when the object type is a supertype of the whole union. As soon as one member is already subtracted (`$a !== $b` narrowing inside a loop over Enum::cases() gets there quickly), the check fails and the members are peeled off one at a time - every peel rebuilds and re-describes the growing subtracted union, so removing 250 cases costs O(cases^2) describes. ObjectType::tryRemove() now drops the members the type no longer holds and subtracts the rest in one go, which is the same set difference. The allowed subtypes go through FiniteTypeSet: subtracted enum cases are matched by FiniteTypeSet::key() (a lookup per case) instead of an equals() sweep over every case, and the allowed subtypes it cannot key (a sealed class hierarchy) keep the sweep. ClassReflection::getAllowedSubTypes() memoises its result instead of rebuilding every case object on each call. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01DfQHLTyyoMfjfa4sXJCGa5 --- src/Reflection/ClassReflection.php | 12 +- src/Type/Constant/ConstantArrayType.php | 4 +- src/Type/ObjectType.php | 53 +- tests/bench/data/enum-case-union-removal.php | 567 +++++++++++++++++++ 4 files changed, 629 insertions(+), 7 deletions(-) create mode 100644 tests/bench/data/enum-case-union-removal.php diff --git a/src/Reflection/ClassReflection.php b/src/Reflection/ClassReflection.php index 3623c8f6ce9..a7b1aefb088 100644 --- a/src/Reflection/ClassReflection.php +++ b/src/Reflection/ClassReflection.php @@ -110,6 +110,11 @@ final class ClassReflection private ?bool $isDeprecated = null; + /** @var array|null */ + private ?array $allowedSubTypes = null; + + private bool $allowedSubTypesResolved = false; + private ?bool $isGeneric = null; private ?bool $isInternal = null; @@ -2330,9 +2335,14 @@ public function getResolvedMixinTypes(): array */ public function getAllowedSubTypes(): ?array { + if ($this->allowedSubTypesResolved) { + return $this->allowedSubTypes; + } + + $this->allowedSubTypesResolved = true; foreach ($this->classReflectionExtensionRegistryProvider->getRegistry()->getAllowedSubTypesClassReflectionExtensions() as $allowedSubTypesClassReflectionExtension) { if ($allowedSubTypesClassReflectionExtension->supports($this)) { - return $allowedSubTypesClassReflectionExtension->getAllowedSubTypes($this); + return $this->allowedSubTypes = $allowedSubTypesClassReflectionExtension->getAllowedSubTypes($this); } } diff --git a/src/Type/Constant/ConstantArrayType.php b/src/Type/Constant/ConstantArrayType.php index 9257a650c6e..b7c9ddd745a 100644 --- a/src/Type/Constant/ConstantArrayType.php +++ b/src/Type/Constant/ConstantArrayType.php @@ -3611,8 +3611,8 @@ public function getFiniteTypes(): array // hundreds of builder clones per call for a result that is thrown away. $finiteValueTypesPerKey = []; $count = 1; - foreach ($this->keyTypes as $i => $keyType) { - $finiteValueTypes = $this->valueTypes[$i]->getFiniteTypes(); + foreach ($this->valueTypes as $i => $valueType) { + $finiteValueTypes = $valueType->getFiniteTypes(); if ($finiteValueTypes === []) { return []; } diff --git a/src/Type/ObjectType.php b/src/Type/ObjectType.php index a9cf87f7d2b..0db90aefa20 100644 --- a/src/Type/ObjectType.php +++ b/src/Type/ObjectType.php @@ -1850,13 +1850,32 @@ private function matchAllowedSubTypes(array $subtractedTypes): ?Type $allowedSubTypesCount = count($allowedSubTypes); $subtractedSubTypes = []; + // Enum cases are finite values: FiniteTypeSet keys them by value identity, so + // a subtracted case is a lookup instead of an equals() sweep over every + // allowed case - quadratic in the enum size. Allowed subtypes it cannot key + // (a sealed class hierarchy) still take the sweep. + $allowedSet = FiniteTypeSet::create(array_values($allowedSubTypes)); + $keyedAllowedSubTypes = $allowedSet !== null ? $allowedSet->getMembers() : []; + $otherAllowedSubTypes = $allowedSet !== null ? $allowedSet->getOthers() : array_values($allowedSubTypes); + foreach ($subtractedTypes as $subType) { - foreach ($allowedSubTypes as $key => $allowedSubType) { + $key = FiniteTypeSet::key($subType); + if ($key !== null) { + if (!array_key_exists($key, $keyedAllowedSubTypes) || !$subType->equals($keyedAllowedSubTypes[$key])) { + return null; + } + + $subtractedSubTypes[] = $subType; + unset($keyedAllowedSubTypes[$key]); + continue; + } + + foreach ($otherAllowedSubTypes as $i => $allowedSubType) { if ($subType->equals($allowedSubType)) { // An allowed subtype is dropped as it matches, so no two matches // can be the same one and the matches need no keying. $subtractedSubTypes[] = $subType; - unset($allowedSubTypes[$key]); + unset($otherAllowedSubTypes[$i]); continue 2; } } @@ -1864,8 +1883,9 @@ private function matchAllowedSubTypes(array $subtractedTypes): ?Type return null; } - if (count($allowedSubTypes) === 1) { - return array_values($allowedSubTypes)[0]; + $remainingAllowedSubTypes = array_merge(array_values($keyedAllowedSubTypes), array_values($otherAllowedSubTypes)); + if (count($remainingAllowedSubTypes) === 1) { + return $remainingAllowedSubTypes[0]; } $subtractedSubTypesCount = count($subtractedSubTypes); @@ -2064,6 +2084,31 @@ public function tryRemove(Type $typeToRemove): ?Type return $this->subtract($typeToRemove); } + $classReflection = $this->getClassReflection(); + if ($typeToRemove instanceof UnionType && $classReflection !== null && $classReflection->getAllowedSubTypes() !== null) { + // A sealed hierarchy subtracts by set difference, so the members this + // type no longer holds (already subtracted) are no-ops and the rest come + // off in one subtraction - the same result as removing them one at a + // time, without rebuilding the subtracted union once per member. + $membersToRemove = []; + foreach ($typeToRemove->getTypes() as $member) { + $isSuperTypeOfMember = $this->isSuperTypeOf($member); + if ($isSuperTypeOfMember->yes()) { + $membersToRemove[] = $member; + continue; + } + if ($isSuperTypeOfMember->maybe()) { + return null; + } + } + + if ($membersToRemove === []) { + return $this; + } + + return $this->subtract(count($membersToRemove) === 1 ? $membersToRemove[0] : new UnionType($membersToRemove)); + } + return null; } diff --git a/tests/bench/data/enum-case-union-removal.php b/tests/bench/data/enum-case-union-removal.php new file mode 100644 index 00000000000..1d9d30c5ac9 --- /dev/null +++ b/tests/bench/data/enum-case-union-removal.php @@ -0,0 +1,567 @@ += 8.1 + +declare(strict_types = 1); + +namespace BenchEnumCaseUnionRemoval; + +/** + * Regression test for removing a union of enum cases from an enum type that already carries a subtraction. + * + * Narrowing `$country !== $onlyCountry` inside a loop over Country::cases() makes + * TypeCombinator::remove() take a union of cases away from an enum type with some cases + * already subtracted. The whole-union shortcut only applied when the type still held every + * case of the union, so the cases were peeled off one at a time and every peel rebuilt and + * re-described the growing subtracted union - quadratic in the number of cases. + * ObjectType::tryRemove() now subtracts the still-held cases in one go. + * + * `bin/phpstan analyse -l 8 --debug` on this file: 3.3 s on 2.3.x, 1.6 s with the fix. + */ +enum Country: string +{ + + case C1 = 'c1'; + case C2 = 'c2'; + case C3 = 'c3'; + case C4 = 'c4'; + case C5 = 'c5'; + case C6 = 'c6'; + case C7 = 'c7'; + case C8 = 'c8'; + case C9 = 'c9'; + case C10 = 'c10'; + case C11 = 'c11'; + case C12 = 'c12'; + case C13 = 'c13'; + case C14 = 'c14'; + case C15 = 'c15'; + case C16 = 'c16'; + case C17 = 'c17'; + case C18 = 'c18'; + case C19 = 'c19'; + case C20 = 'c20'; + case C21 = 'c21'; + case C22 = 'c22'; + case C23 = 'c23'; + case C24 = 'c24'; + case C25 = 'c25'; + case C26 = 'c26'; + case C27 = 'c27'; + case C28 = 'c28'; + case C29 = 'c29'; + case C30 = 'c30'; + case C31 = 'c31'; + case C32 = 'c32'; + case C33 = 'c33'; + case C34 = 'c34'; + case C35 = 'c35'; + case C36 = 'c36'; + case C37 = 'c37'; + case C38 = 'c38'; + case C39 = 'c39'; + case C40 = 'c40'; + case C41 = 'c41'; + case C42 = 'c42'; + case C43 = 'c43'; + case C44 = 'c44'; + case C45 = 'c45'; + case C46 = 'c46'; + case C47 = 'c47'; + case C48 = 'c48'; + case C49 = 'c49'; + case C50 = 'c50'; + case C51 = 'c51'; + case C52 = 'c52'; + case C53 = 'c53'; + case C54 = 'c54'; + case C55 = 'c55'; + case C56 = 'c56'; + case C57 = 'c57'; + case C58 = 'c58'; + case C59 = 'c59'; + case C60 = 'c60'; + case C61 = 'c61'; + case C62 = 'c62'; + case C63 = 'c63'; + case C64 = 'c64'; + case C65 = 'c65'; + case C66 = 'c66'; + case C67 = 'c67'; + case C68 = 'c68'; + case C69 = 'c69'; + case C70 = 'c70'; + case C71 = 'c71'; + case C72 = 'c72'; + case C73 = 'c73'; + case C74 = 'c74'; + case C75 = 'c75'; + case C76 = 'c76'; + case C77 = 'c77'; + case C78 = 'c78'; + case C79 = 'c79'; + case C80 = 'c80'; + case C81 = 'c81'; + case C82 = 'c82'; + case C83 = 'c83'; + case C84 = 'c84'; + case C85 = 'c85'; + case C86 = 'c86'; + case C87 = 'c87'; + case C88 = 'c88'; + case C89 = 'c89'; + case C90 = 'c90'; + case C91 = 'c91'; + case C92 = 'c92'; + case C93 = 'c93'; + case C94 = 'c94'; + case C95 = 'c95'; + case C96 = 'c96'; + case C97 = 'c97'; + case C98 = 'c98'; + case C99 = 'c99'; + case C100 = 'c100'; + case C101 = 'c101'; + case C102 = 'c102'; + case C103 = 'c103'; + case C104 = 'c104'; + case C105 = 'c105'; + case C106 = 'c106'; + case C107 = 'c107'; + case C108 = 'c108'; + case C109 = 'c109'; + case C110 = 'c110'; + case C111 = 'c111'; + case C112 = 'c112'; + case C113 = 'c113'; + case C114 = 'c114'; + case C115 = 'c115'; + case C116 = 'c116'; + case C117 = 'c117'; + case C118 = 'c118'; + case C119 = 'c119'; + case C120 = 'c120'; + case C121 = 'c121'; + case C122 = 'c122'; + case C123 = 'c123'; + case C124 = 'c124'; + case C125 = 'c125'; + case C126 = 'c126'; + case C127 = 'c127'; + case C128 = 'c128'; + case C129 = 'c129'; + case C130 = 'c130'; + case C131 = 'c131'; + case C132 = 'c132'; + case C133 = 'c133'; + case C134 = 'c134'; + case C135 = 'c135'; + case C136 = 'c136'; + case C137 = 'c137'; + case C138 = 'c138'; + case C139 = 'c139'; + case C140 = 'c140'; + case C141 = 'c141'; + case C142 = 'c142'; + case C143 = 'c143'; + case C144 = 'c144'; + case C145 = 'c145'; + case C146 = 'c146'; + case C147 = 'c147'; + case C148 = 'c148'; + case C149 = 'c149'; + case C150 = 'c150'; + case C151 = 'c151'; + case C152 = 'c152'; + case C153 = 'c153'; + case C154 = 'c154'; + case C155 = 'c155'; + case C156 = 'c156'; + case C157 = 'c157'; + case C158 = 'c158'; + case C159 = 'c159'; + case C160 = 'c160'; + case C161 = 'c161'; + case C162 = 'c162'; + case C163 = 'c163'; + case C164 = 'c164'; + case C165 = 'c165'; + case C166 = 'c166'; + case C167 = 'c167'; + case C168 = 'c168'; + case C169 = 'c169'; + case C170 = 'c170'; + case C171 = 'c171'; + case C172 = 'c172'; + case C173 = 'c173'; + case C174 = 'c174'; + case C175 = 'c175'; + case C176 = 'c176'; + case C177 = 'c177'; + case C178 = 'c178'; + case C179 = 'c179'; + case C180 = 'c180'; + case C181 = 'c181'; + case C182 = 'c182'; + case C183 = 'c183'; + case C184 = 'c184'; + case C185 = 'c185'; + case C186 = 'c186'; + case C187 = 'c187'; + case C188 = 'c188'; + case C189 = 'c189'; + case C190 = 'c190'; + case C191 = 'c191'; + case C192 = 'c192'; + case C193 = 'c193'; + case C194 = 'c194'; + case C195 = 'c195'; + case C196 = 'c196'; + case C197 = 'c197'; + case C198 = 'c198'; + case C199 = 'c199'; + case C200 = 'c200'; + case C201 = 'c201'; + case C202 = 'c202'; + case C203 = 'c203'; + case C204 = 'c204'; + case C205 = 'c205'; + case C206 = 'c206'; + case C207 = 'c207'; + case C208 = 'c208'; + case C209 = 'c209'; + case C210 = 'c210'; + case C211 = 'c211'; + case C212 = 'c212'; + case C213 = 'c213'; + case C214 = 'c214'; + case C215 = 'c215'; + case C216 = 'c216'; + case C217 = 'c217'; + case C218 = 'c218'; + case C219 = 'c219'; + case C220 = 'c220'; + case C221 = 'c221'; + case C222 = 'c222'; + case C223 = 'c223'; + case C224 = 'c224'; + case C225 = 'c225'; + case C226 = 'c226'; + case C227 = 'c227'; + case C228 = 'c228'; + case C229 = 'c229'; + case C230 = 'c230'; + case C231 = 'c231'; + case C232 = 'c232'; + case C233 = 'c233'; + case C234 = 'c234'; + case C235 = 'c235'; + case C236 = 'c236'; + case C237 = 'c237'; + case C238 = 'c238'; + case C239 = 'c239'; + case C240 = 'c240'; + case C241 = 'c241'; + case C242 = 'c242'; + case C243 = 'c243'; + case C244 = 'c244'; + case C245 = 'c245'; + case C246 = 'c246'; + case C247 = 'c247'; + case C248 = 'c248'; + case C249 = 'c249'; + case C250 = 'c250'; + case C251 = 'c251'; + case C252 = 'c252'; + case C253 = 'c253'; + case C254 = 'c254'; + case C255 = 'c255'; + case C256 = 'c256'; + case C257 = 'c257'; + case C258 = 'c258'; + case C259 = 'c259'; + case C260 = 'c260'; + case C261 = 'c261'; + case C262 = 'c262'; + case C263 = 'c263'; + case C264 = 'c264'; + case C265 = 'c265'; + case C266 = 'c266'; + case C267 = 'c267'; + case C268 = 'c268'; + case C269 = 'c269'; + case C270 = 'c270'; + case C271 = 'c271'; + case C272 = 'c272'; + case C273 = 'c273'; + case C274 = 'c274'; + case C275 = 'c275'; + case C276 = 'c276'; + case C277 = 'c277'; + case C278 = 'c278'; + case C279 = 'c279'; + case C280 = 'c280'; + case C281 = 'c281'; + case C282 = 'c282'; + case C283 = 'c283'; + case C284 = 'c284'; + case C285 = 'c285'; + case C286 = 'c286'; + case C287 = 'c287'; + case C288 = 'c288'; + case C289 = 'c289'; + case C290 = 'c290'; + case C291 = 'c291'; + case C292 = 'c292'; + case C293 = 'c293'; + case C294 = 'c294'; + case C295 = 'c295'; + case C296 = 'c296'; + case C297 = 'c297'; + case C298 = 'c298'; + case C299 = 'c299'; + case C300 = 'c300'; + case C301 = 'c301'; + case C302 = 'c302'; + case C303 = 'c303'; + case C304 = 'c304'; + case C305 = 'c305'; + case C306 = 'c306'; + case C307 = 'c307'; + case C308 = 'c308'; + case C309 = 'c309'; + case C310 = 'c310'; + case C311 = 'c311'; + case C312 = 'c312'; + case C313 = 'c313'; + case C314 = 'c314'; + case C315 = 'c315'; + case C316 = 'c316'; + case C317 = 'c317'; + case C318 = 'c318'; + case C319 = 'c319'; + case C320 = 'c320'; + case C321 = 'c321'; + case C322 = 'c322'; + case C323 = 'c323'; + case C324 = 'c324'; + case C325 = 'c325'; + case C326 = 'c326'; + case C327 = 'c327'; + case C328 = 'c328'; + case C329 = 'c329'; + case C330 = 'c330'; + case C331 = 'c331'; + case C332 = 'c332'; + case C333 = 'c333'; + case C334 = 'c334'; + case C335 = 'c335'; + case C336 = 'c336'; + case C337 = 'c337'; + case C338 = 'c338'; + case C339 = 'c339'; + case C340 = 'c340'; + case C341 = 'c341'; + case C342 = 'c342'; + case C343 = 'c343'; + case C344 = 'c344'; + case C345 = 'c345'; + case C346 = 'c346'; + case C347 = 'c347'; + case C348 = 'c348'; + case C349 = 'c349'; + case C350 = 'c350'; + case C351 = 'c351'; + case C352 = 'c352'; + case C353 = 'c353'; + case C354 = 'c354'; + case C355 = 'c355'; + case C356 = 'c356'; + case C357 = 'c357'; + case C358 = 'c358'; + case C359 = 'c359'; + case C360 = 'c360'; + case C361 = 'c361'; + case C362 = 'c362'; + case C363 = 'c363'; + case C364 = 'c364'; + case C365 = 'c365'; + case C366 = 'c366'; + case C367 = 'c367'; + case C368 = 'c368'; + case C369 = 'c369'; + case C370 = 'c370'; + case C371 = 'c371'; + case C372 = 'c372'; + case C373 = 'c373'; + case C374 = 'c374'; + case C375 = 'c375'; + case C376 = 'c376'; + case C377 = 'c377'; + case C378 = 'c378'; + case C379 = 'c379'; + case C380 = 'c380'; + case C381 = 'c381'; + case C382 = 'c382'; + case C383 = 'c383'; + case C384 = 'c384'; + case C385 = 'c385'; + case C386 = 'c386'; + case C387 = 'c387'; + case C388 = 'c388'; + case C389 = 'c389'; + case C390 = 'c390'; + case C391 = 'c391'; + case C392 = 'c392'; + case C393 = 'c393'; + case C394 = 'c394'; + case C395 = 'c395'; + case C396 = 'c396'; + case C397 = 'c397'; + case C398 = 'c398'; + case C399 = 'c399'; + case C400 = 'c400'; + case C401 = 'c401'; + case C402 = 'c402'; + case C403 = 'c403'; + case C404 = 'c404'; + case C405 = 'c405'; + case C406 = 'c406'; + case C407 = 'c407'; + case C408 = 'c408'; + case C409 = 'c409'; + case C410 = 'c410'; + case C411 = 'c411'; + case C412 = 'c412'; + case C413 = 'c413'; + case C414 = 'c414'; + case C415 = 'c415'; + case C416 = 'c416'; + case C417 = 'c417'; + case C418 = 'c418'; + case C419 = 'c419'; + case C420 = 'c420'; + case C421 = 'c421'; + case C422 = 'c422'; + case C423 = 'c423'; + case C424 = 'c424'; + case C425 = 'c425'; + case C426 = 'c426'; + case C427 = 'c427'; + case C428 = 'c428'; + case C429 = 'c429'; + case C430 = 'c430'; + case C431 = 'c431'; + case C432 = 'c432'; + case C433 = 'c433'; + case C434 = 'c434'; + case C435 = 'c435'; + case C436 = 'c436'; + case C437 = 'c437'; + case C438 = 'c438'; + case C439 = 'c439'; + case C440 = 'c440'; + case C441 = 'c441'; + case C442 = 'c442'; + case C443 = 'c443'; + case C444 = 'c444'; + case C445 = 'c445'; + case C446 = 'c446'; + case C447 = 'c447'; + case C448 = 'c448'; + case C449 = 'c449'; + case C450 = 'c450'; + case C451 = 'c451'; + case C452 = 'c452'; + case C453 = 'c453'; + case C454 = 'c454'; + case C455 = 'c455'; + case C456 = 'c456'; + case C457 = 'c457'; + case C458 = 'c458'; + case C459 = 'c459'; + case C460 = 'c460'; + case C461 = 'c461'; + case C462 = 'c462'; + case C463 = 'c463'; + case C464 = 'c464'; + case C465 = 'c465'; + case C466 = 'c466'; + case C467 = 'c467'; + case C468 = 'c468'; + case C469 = 'c469'; + case C470 = 'c470'; + case C471 = 'c471'; + case C472 = 'c472'; + case C473 = 'c473'; + case C474 = 'c474'; + case C475 = 'c475'; + case C476 = 'c476'; + case C477 = 'c477'; + case C478 = 'c478'; + case C479 = 'c479'; + case C480 = 'c480'; + case C481 = 'c481'; + case C482 = 'c482'; + case C483 = 'c483'; + case C484 = 'c484'; + case C485 = 'c485'; + case C486 = 'c486'; + case C487 = 'c487'; + case C488 = 'c488'; + case C489 = 'c489'; + case C490 = 'c490'; + case C491 = 'c491'; + case C492 = 'c492'; + case C493 = 'c493'; + case C494 = 'c494'; + case C495 = 'c495'; + case C496 = 'c496'; + case C497 = 'c497'; + case C498 = 'c498'; + case C499 = 'c499'; + case C500 = 'c500'; + +} + +final class Importer +{ + + public function run(?Country $onlyCountry, ?Country $startCountry, bool $onlyMissing): void + { + foreach (Country::cases() as $country) { + if ($onlyCountry !== null && $country !== $onlyCountry) { + continue; + } + + if ($startCountry !== null && $country !== $startCountry) { + continue; + } + + // Start country has been found - clear it to stop skipping + $startCountry = null; + + try { + if ($onlyMissing && $this->count($country) > 0) { + continue; + } + + $this->import($country); + } finally { + $this->clear(); + } + } + } + + private function count(Country $country): int + { + return strlen($country->value); + } + + private function import(Country $country): void + { + } + + private function clear(): void + { + } + +} From 0375bfba2e9d7ad0e7d2c2ab4ca53200785a8f27 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Mon, 14 Sep 2026 14:32:08 +0200 Subject: [PATCH 3/7] Drop repeated members and flatten in one pass in TypeCombinator::doUnion() A member passed to union() more than once contributes nothing, but the pairwise comparison still paid for every repeat - and array_values() of a shape with optional keys unions the same value type once per slot, so a 250-entry map built in a loop over an enum cost 10 s in one call. The repeats are dropped by identity before anything else. The flattening loop also rebuilt the argument list with array_splice() once per union member, quadratic in the number of members; it is a single pass now. array_merge() hands the first array back as it is when the second one is empty, so the keys the bucketing unset are renumbered inside the merge argument. build/spl-autoload-functions-pre-php-7.neon only ignored the "array_values is already a list" report that the old standalone renumbering produced on PHP < 8 (the array_merge() stub returns a list there); nothing reports it any more, so the file and its include go. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01DfQHLTyyoMfjfa4sXJCGa5 --- build/ignore-by-php-version.neon.php | 4 +- build/spl-autoload-functions-pre-php-7.neon | 5 -- src/Type/TypeCombinator.php | 76 +++++++++++++------ .../data/array-values-literal-keyed-map.php | 44 +++++++++++ 4 files changed, 96 insertions(+), 33 deletions(-) delete mode 100644 build/spl-autoload-functions-pre-php-7.neon create mode 100644 tests/bench/data/array-values-literal-keyed-map.php diff --git a/build/ignore-by-php-version.neon.php b/build/ignore-by-php-version.neon.php index 1eaaa6863dc..44d5354d931 100644 --- a/build/ignore-by-php-version.neon.php +++ b/build/ignore-by-php-version.neon.php @@ -21,9 +21,7 @@ $includes[] = __DIR__ . '/more-enum-adapter-errors.neon'; } -if (PHP_VERSION_ID < 80000) { - $includes[] = __DIR__ . '/spl-autoload-functions-pre-php-7.neon'; -} else { +if (PHP_VERSION_ID >= 80000) { $includes[] = __DIR__ . '/spl-autoload-functions-php-8.neon'; } diff --git a/build/spl-autoload-functions-pre-php-7.neon b/build/spl-autoload-functions-pre-php-7.neon deleted file mode 100644 index 42cd820e71d..00000000000 --- a/build/spl-autoload-functions-pre-php-7.neon +++ /dev/null @@ -1,5 +0,0 @@ -parameters: - ignoreErrors: - - - message: '#^Parameter \#1 \$array \(list\) of array_values is already a list, call has no effect\.$#' - path: ../src/Type/TypeCombinator.php diff --git a/src/Type/TypeCombinator.php b/src/Type/TypeCombinator.php index 86f54a799d5..ef19595cc24 100644 --- a/src/Type/TypeCombinator.php +++ b/src/Type/TypeCombinator.php @@ -43,6 +43,7 @@ use function get_class; use function implode; use function in_array; +use function spl_object_id; use function sprintf; use function usort; use const PHP_INT_MAX; @@ -293,52 +294,76 @@ public static function doUnion(Type ...$types): Type } } + // A member passed more than once contributes nothing; dropping the + // repeats up front keeps the pairwise comparison below from paying for + // them (array_values() of a shape unions the same value type per slot). + if ($typesCount > 2) { + $seenTypes = []; + $uniqueTypes = []; + foreach ($types as $type) { + $typeId = spl_object_id($type); + if (isset($seenTypes[$typeId])) { + continue; + } + $seenTypes[$typeId] = true; + $uniqueTypes[] = $type; + } + if (count($uniqueTypes) === 1) { + return $uniqueTypes[0]; + } + if (count($uniqueTypes) === 2) { + return self::union($uniqueTypes[0], $uniqueTypes[1]); + } + $types = $uniqueTypes; + } + $alreadyNormalized = []; $alreadyNormalizedCounter = 0; $benevolentTypes = []; $neverCount = 0; - // transform A | (B | C) to A | B | C - for ($i = 0; $i < $typesCount; $i++) { + // transform A | (B | C) to A | B | C - in one pass, a union's members are + // never unions, implicit never or implicit mixed themselves + $flattenedTypes = []; + foreach ($types as $type) { if ( - $types[$i] instanceof MixedType - && !$types[$i]->isExplicitMixed() - && !$types[$i] instanceof TemplateMixedType - && $types[$i]->getSubtractedType() === null + $type instanceof MixedType + && !$type->isExplicitMixed() + && !$type instanceof TemplateMixedType + && $type->getSubtractedType() === null ) { - return $types[$i]; + return $type; } - if ($types[$i] instanceof NeverType && !$types[$i]->isExplicit()) { + if ($type instanceof NeverType && !$type->isExplicit()) { $neverCount++; + $flattenedTypes[] = $type; continue; } - if ($types[$i] instanceof BenevolentUnionType) { - if ($types[$i] instanceof TemplateType) { + if ($type instanceof BenevolentUnionType) { + if ($type instanceof TemplateType) { + $flattenedTypes[] = $type; continue; } - $benevolentTypesCount = 0; - $typesInner = $types[$i]->getTypes(); - foreach ($typesInner as $benevolentInnerType) { - $benevolentTypesCount++; + foreach ($type->getTypes() as $benevolentInnerType) { $benevolentTypes[$benevolentInnerType->describe(VerbosityLevel::value())] = $benevolentInnerType; + $flattenedTypes[] = $benevolentInnerType; } - array_splice($types, $i, 1, $typesInner); - $typesCount += $benevolentTypesCount - 1; continue; } - if (!($types[$i] instanceof UnionType)) { - continue; - } - if ($types[$i] instanceof TemplateType) { + if (!($type instanceof UnionType) || $type instanceof TemplateType) { + $flattenedTypes[] = $type; continue; } - $typesInner = $types[$i]->getTypes(); + $typesInner = $type->getTypes(); $alreadyNormalized[$alreadyNormalizedCounter] = $typesInner; $alreadyNormalizedCounter++; - array_splice($types, $i, 1, $typesInner); - $typesCount += count($typesInner) - 1; + foreach ($typesInner as $innerType) { + $flattenedTypes[] = $innerType; + } } + $types = $flattenedTypes; + $typesCount = count($types); // Bulk-remove implicit NeverTypes (skipped during the loop above) if ($neverCount > 0) { @@ -427,8 +452,9 @@ public static function doUnion(Type ...$types): Type static fn (IntegerRangeType $a, IntegerRangeType $b): int => ($a->getMin() ?? PHP_INT_MIN) <=> ($b->getMin() ?? PHP_INT_MIN) ?: ($a->getMax() ?? PHP_INT_MAX) <=> ($b->getMax() ?? PHP_INT_MAX), ); - $types = array_merge($types, $integerRangeTypes); - $types = array_values($types); + // array_merge() hands the first array back as it is when the second one + // is empty, so the keys the bucketing above unset must be renumbered here + $types = array_merge(array_values($types), $integerRangeTypes); $typesCount = count($types); foreach ($scalarTypes as $classType => $scalarTypeItems) { diff --git a/tests/bench/data/array-values-literal-keyed-map.php b/tests/bench/data/array-values-literal-keyed-map.php new file mode 100644 index 00000000000..13251ffb443 --- /dev/null +++ b/tests/bench/data/array-values-literal-keyed-map.php @@ -0,0 +1,44 @@ + $countries + * @param list $partialCountries + * @return list + */ +function collect(array $countries, array $partialCountries): array +{ + $values = []; + foreach ([$countries, $partialCountries] as $activeCountries) { + foreach ($activeCountries as $country) { + $values[$country->getValue()] = $country->getValue(); + } + } + + // Sort to make each combination unique + ksort($values); + + return array_values($values); +} From 6e23771c5b0959d5ab6cb8bdaaee053d0e67b96b Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Mon, 14 Sep 2026 16:42:03 +0200 Subject: [PATCH 4/7] Keep the key union when writing a constant offset it already holds ArrayType::setOffsetValueType() unions the key type with the offset for every constant offset written, and TypeCombinator::union() rebuilt a union that already held the offset: every member was re-bucketed by its description and a new union assembled. A rule checking a write into an array keyed by a union of a few hundred locale strings paid that once per member of the offset type. The key union is now handed back untouched when it is a supertype of the offset. The check lives in ArrayType rather than in TypeCombinator::union(). The array type and its key union live on across the writes, so the union's finite value index is built once and pays off; asking it of every union TypeCombinator sees built that index for short-lived unions that are asked once, which made the bug-12671 bench file 8% slower. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01DfQHLTyyoMfjfa4sXJCGa5 --- src/Type/ArrayType.php | 27 +- .../data/literal-key-union-offset-write.php | 4523 +++++++++++++++++ 2 files changed, 4549 insertions(+), 1 deletion(-) create mode 100644 tests/bench/data/literal-key-union-offset-write.php diff --git a/src/Type/ArrayType.php b/src/Type/ArrayType.php index 300f5ae7875..66810275050 100644 --- a/src/Type/ArrayType.php +++ b/src/Type/ArrayType.php @@ -28,6 +28,7 @@ use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\Generic\TemplateMixedType; use PHPStan\Type\Generic\TemplateStrictMixedType; +use PHPStan\Type\Generic\TemplateType; use PHPStan\Type\Generic\TemplateTypeMap; use PHPStan\Type\Generic\TemplateTypeVariance; use PHPStan\Type\Traits\ArrayTypeTrait; @@ -406,7 +407,7 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $uni return new IntersectionType([ $this->withTypes( - TypeCombinator::union($this->keyType, $offsetType), + $this->unionKeyTypeWithConstantOffset($offsetType), TypeCombinator::union($this->itemType, $valueType), ), new HasOffsetValueType($offsetType, $valueType), @@ -423,6 +424,30 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $uni ]); } + /** + * The key type with a constant offset written into the array. + * + * A key union that already holds the offset is handed back as it is. Unioning would + * rebuild the same members, and an array keyed by a union of a few hundred literals + * pays that rebuild for every key written. The array type - and its key union - lives + * on across the writes, so the membership check pays for the union's finite value + * index once; asking it of every union TypeCombinator sees would build that index for + * short-lived unions that are never asked again. + */ + private function unionKeyTypeWithConstantOffset(Type $offsetType): Type + { + if ( + $this->keyType instanceof UnionType + && !$this->keyType instanceof BenevolentUnionType + && !$this->keyType instanceof TemplateType + && $this->keyType->isSuperTypeOf($offsetType)->yes() + ) { + return $this->keyType; + } + + return TypeCombinator::union($this->keyType, $offsetType); + } + public function setExistingOffsetValueType(Type $offsetType, Type $valueType): Type { if ($this->itemType->isConstantArray()->yes() && $valueType->isConstantArray()->yes()) { diff --git a/tests/bench/data/literal-key-union-offset-write.php b/tests/bench/data/literal-key-union-offset-write.php new file mode 100644 index 00000000000..cbb8633dcda --- /dev/null +++ b/tests/bench/data/literal-key-union-offset-write.php @@ -0,0 +1,4523 @@ + $a + */ +function write(array $a): void +{ + $b = $a; + $b['l1'] = 1; + echo $b['l1']; + $b = $a; + $b['l2'] = 2; + echo $b['l2']; + $b = $a; + $b['l3'] = 3; + echo $b['l3']; + $b = $a; + $b['l4'] = 4; + echo $b['l4']; + $b = $a; + $b['l5'] = 5; + echo $b['l5']; + $b = $a; + $b['l6'] = 6; + echo $b['l6']; + $b = $a; + $b['l7'] = 7; + echo $b['l7']; + $b = $a; + $b['l8'] = 8; + echo $b['l8']; + $b = $a; + $b['l9'] = 9; + echo $b['l9']; + $b = $a; + $b['l10'] = 10; + echo $b['l10']; + $b = $a; + $b['l11'] = 11; + echo $b['l11']; + $b = $a; + $b['l12'] = 12; + echo $b['l12']; + $b = $a; + $b['l13'] = 13; + echo $b['l13']; + $b = $a; + $b['l14'] = 14; + echo $b['l14']; + $b = $a; + $b['l15'] = 15; + echo $b['l15']; + $b = $a; + $b['l16'] = 16; + echo $b['l16']; + $b = $a; + $b['l17'] = 17; + echo $b['l17']; + $b = $a; + $b['l18'] = 18; + echo $b['l18']; + $b = $a; + $b['l19'] = 19; + echo $b['l19']; + $b = $a; + $b['l20'] = 20; + echo $b['l20']; + $b = $a; + $b['l21'] = 21; + echo $b['l21']; + $b = $a; + $b['l22'] = 22; + echo $b['l22']; + $b = $a; + $b['l23'] = 23; + echo $b['l23']; + $b = $a; + $b['l24'] = 24; + echo $b['l24']; + $b = $a; + $b['l25'] = 25; + echo $b['l25']; + $b = $a; + $b['l26'] = 26; + echo $b['l26']; + $b = $a; + $b['l27'] = 27; + echo $b['l27']; + $b = $a; + $b['l28'] = 28; + echo $b['l28']; + $b = $a; + $b['l29'] = 29; + echo $b['l29']; + $b = $a; + $b['l30'] = 30; + echo $b['l30']; + $b = $a; + $b['l31'] = 31; + echo $b['l31']; + $b = $a; + $b['l32'] = 32; + echo $b['l32']; + $b = $a; + $b['l33'] = 33; + echo $b['l33']; + $b = $a; + $b['l34'] = 34; + echo $b['l34']; + $b = $a; + $b['l35'] = 35; + echo $b['l35']; + $b = $a; + $b['l36'] = 36; + echo $b['l36']; + $b = $a; + $b['l37'] = 37; + echo $b['l37']; + $b = $a; + $b['l38'] = 38; + echo $b['l38']; + $b = $a; + $b['l39'] = 39; + echo $b['l39']; + $b = $a; + $b['l40'] = 40; + echo $b['l40']; + $b = $a; + $b['l41'] = 41; + echo $b['l41']; + $b = $a; + $b['l42'] = 42; + echo $b['l42']; + $b = $a; + $b['l43'] = 43; + echo $b['l43']; + $b = $a; + $b['l44'] = 44; + echo $b['l44']; + $b = $a; + $b['l45'] = 45; + echo $b['l45']; + $b = $a; + $b['l46'] = 46; + echo $b['l46']; + $b = $a; + $b['l47'] = 47; + echo $b['l47']; + $b = $a; + $b['l48'] = 48; + echo $b['l48']; + $b = $a; + $b['l49'] = 49; + echo $b['l49']; + $b = $a; + $b['l50'] = 50; + echo $b['l50']; + $b = $a; + $b['l51'] = 51; + echo $b['l51']; + $b = $a; + $b['l52'] = 52; + echo $b['l52']; + $b = $a; + $b['l53'] = 53; + echo $b['l53']; + $b = $a; + $b['l54'] = 54; + echo $b['l54']; + $b = $a; + $b['l55'] = 55; + echo $b['l55']; + $b = $a; + $b['l56'] = 56; + echo $b['l56']; + $b = $a; + $b['l57'] = 57; + echo $b['l57']; + $b = $a; + $b['l58'] = 58; + echo $b['l58']; + $b = $a; + $b['l59'] = 59; + echo $b['l59']; + $b = $a; + $b['l60'] = 60; + echo $b['l60']; + $b = $a; + $b['l61'] = 61; + echo $b['l61']; + $b = $a; + $b['l62'] = 62; + echo $b['l62']; + $b = $a; + $b['l63'] = 63; + echo $b['l63']; + $b = $a; + $b['l64'] = 64; + echo $b['l64']; + $b = $a; + $b['l65'] = 65; + echo $b['l65']; + $b = $a; + $b['l66'] = 66; + echo $b['l66']; + $b = $a; + $b['l67'] = 67; + echo $b['l67']; + $b = $a; + $b['l68'] = 68; + echo $b['l68']; + $b = $a; + $b['l69'] = 69; + echo $b['l69']; + $b = $a; + $b['l70'] = 70; + echo $b['l70']; + $b = $a; + $b['l71'] = 71; + echo $b['l71']; + $b = $a; + $b['l72'] = 72; + echo $b['l72']; + $b = $a; + $b['l73'] = 73; + echo $b['l73']; + $b = $a; + $b['l74'] = 74; + echo $b['l74']; + $b = $a; + $b['l75'] = 75; + echo $b['l75']; + $b = $a; + $b['l76'] = 76; + echo $b['l76']; + $b = $a; + $b['l77'] = 77; + echo $b['l77']; + $b = $a; + $b['l78'] = 78; + echo $b['l78']; + $b = $a; + $b['l79'] = 79; + echo $b['l79']; + $b = $a; + $b['l80'] = 80; + echo $b['l80']; + $b = $a; + $b['l81'] = 81; + echo $b['l81']; + $b = $a; + $b['l82'] = 82; + echo $b['l82']; + $b = $a; + $b['l83'] = 83; + echo $b['l83']; + $b = $a; + $b['l84'] = 84; + echo $b['l84']; + $b = $a; + $b['l85'] = 85; + echo $b['l85']; + $b = $a; + $b['l86'] = 86; + echo $b['l86']; + $b = $a; + $b['l87'] = 87; + echo $b['l87']; + $b = $a; + $b['l88'] = 88; + echo $b['l88']; + $b = $a; + $b['l89'] = 89; + echo $b['l89']; + $b = $a; + $b['l90'] = 90; + echo $b['l90']; + $b = $a; + $b['l91'] = 91; + echo $b['l91']; + $b = $a; + $b['l92'] = 92; + echo $b['l92']; + $b = $a; + $b['l93'] = 93; + echo $b['l93']; + $b = $a; + $b['l94'] = 94; + echo $b['l94']; + $b = $a; + $b['l95'] = 95; + echo $b['l95']; + $b = $a; + $b['l96'] = 96; + echo $b['l96']; + $b = $a; + $b['l97'] = 97; + echo $b['l97']; + $b = $a; + $b['l98'] = 98; + echo $b['l98']; + $b = $a; + $b['l99'] = 99; + echo $b['l99']; + $b = $a; + $b['l100'] = 100; + echo $b['l100']; + $b = $a; + $b['l101'] = 101; + echo $b['l101']; + $b = $a; + $b['l102'] = 102; + echo $b['l102']; + $b = $a; + $b['l103'] = 103; + echo $b['l103']; + $b = $a; + $b['l104'] = 104; + echo $b['l104']; + $b = $a; + $b['l105'] = 105; + echo $b['l105']; + $b = $a; + $b['l106'] = 106; + echo $b['l106']; + $b = $a; + $b['l107'] = 107; + echo $b['l107']; + $b = $a; + $b['l108'] = 108; + echo $b['l108']; + $b = $a; + $b['l109'] = 109; + echo $b['l109']; + $b = $a; + $b['l110'] = 110; + echo $b['l110']; + $b = $a; + $b['l111'] = 111; + echo $b['l111']; + $b = $a; + $b['l112'] = 112; + echo $b['l112']; + $b = $a; + $b['l113'] = 113; + echo $b['l113']; + $b = $a; + $b['l114'] = 114; + echo $b['l114']; + $b = $a; + $b['l115'] = 115; + echo $b['l115']; + $b = $a; + $b['l116'] = 116; + echo $b['l116']; + $b = $a; + $b['l117'] = 117; + echo $b['l117']; + $b = $a; + $b['l118'] = 118; + echo $b['l118']; + $b = $a; + $b['l119'] = 119; + echo $b['l119']; + $b = $a; + $b['l120'] = 120; + echo $b['l120']; + $b = $a; + $b['l121'] = 121; + echo $b['l121']; + $b = $a; + $b['l122'] = 122; + echo $b['l122']; + $b = $a; + $b['l123'] = 123; + echo $b['l123']; + $b = $a; + $b['l124'] = 124; + echo $b['l124']; + $b = $a; + $b['l125'] = 125; + echo $b['l125']; + $b = $a; + $b['l126'] = 126; + echo $b['l126']; + $b = $a; + $b['l127'] = 127; + echo $b['l127']; + $b = $a; + $b['l128'] = 128; + echo $b['l128']; + $b = $a; + $b['l129'] = 129; + echo $b['l129']; + $b = $a; + $b['l130'] = 130; + echo $b['l130']; + $b = $a; + $b['l131'] = 131; + echo $b['l131']; + $b = $a; + $b['l132'] = 132; + echo $b['l132']; + $b = $a; + $b['l133'] = 133; + echo $b['l133']; + $b = $a; + $b['l134'] = 134; + echo $b['l134']; + $b = $a; + $b['l135'] = 135; + echo $b['l135']; + $b = $a; + $b['l136'] = 136; + echo $b['l136']; + $b = $a; + $b['l137'] = 137; + echo $b['l137']; + $b = $a; + $b['l138'] = 138; + echo $b['l138']; + $b = $a; + $b['l139'] = 139; + echo $b['l139']; + $b = $a; + $b['l140'] = 140; + echo $b['l140']; + $b = $a; + $b['l141'] = 141; + echo $b['l141']; + $b = $a; + $b['l142'] = 142; + echo $b['l142']; + $b = $a; + $b['l143'] = 143; + echo $b['l143']; + $b = $a; + $b['l144'] = 144; + echo $b['l144']; + $b = $a; + $b['l145'] = 145; + echo $b['l145']; + $b = $a; + $b['l146'] = 146; + echo $b['l146']; + $b = $a; + $b['l147'] = 147; + echo $b['l147']; + $b = $a; + $b['l148'] = 148; + echo $b['l148']; + $b = $a; + $b['l149'] = 149; + echo $b['l149']; + $b = $a; + $b['l150'] = 150; + echo $b['l150']; + $b = $a; + $b['l151'] = 151; + echo $b['l151']; + $b = $a; + $b['l152'] = 152; + echo $b['l152']; + $b = $a; + $b['l153'] = 153; + echo $b['l153']; + $b = $a; + $b['l154'] = 154; + echo $b['l154']; + $b = $a; + $b['l155'] = 155; + echo $b['l155']; + $b = $a; + $b['l156'] = 156; + echo $b['l156']; + $b = $a; + $b['l157'] = 157; + echo $b['l157']; + $b = $a; + $b['l158'] = 158; + echo $b['l158']; + $b = $a; + $b['l159'] = 159; + echo $b['l159']; + $b = $a; + $b['l160'] = 160; + echo $b['l160']; + $b = $a; + $b['l161'] = 161; + echo $b['l161']; + $b = $a; + $b['l162'] = 162; + echo $b['l162']; + $b = $a; + $b['l163'] = 163; + echo $b['l163']; + $b = $a; + $b['l164'] = 164; + echo $b['l164']; + $b = $a; + $b['l165'] = 165; + echo $b['l165']; + $b = $a; + $b['l166'] = 166; + echo $b['l166']; + $b = $a; + $b['l167'] = 167; + echo $b['l167']; + $b = $a; + $b['l168'] = 168; + echo $b['l168']; + $b = $a; + $b['l169'] = 169; + echo $b['l169']; + $b = $a; + $b['l170'] = 170; + echo $b['l170']; + $b = $a; + $b['l171'] = 171; + echo $b['l171']; + $b = $a; + $b['l172'] = 172; + echo $b['l172']; + $b = $a; + $b['l173'] = 173; + echo $b['l173']; + $b = $a; + $b['l174'] = 174; + echo $b['l174']; + $b = $a; + $b['l175'] = 175; + echo $b['l175']; + $b = $a; + $b['l176'] = 176; + echo $b['l176']; + $b = $a; + $b['l177'] = 177; + echo $b['l177']; + $b = $a; + $b['l178'] = 178; + echo $b['l178']; + $b = $a; + $b['l179'] = 179; + echo $b['l179']; + $b = $a; + $b['l180'] = 180; + echo $b['l180']; + $b = $a; + $b['l181'] = 181; + echo $b['l181']; + $b = $a; + $b['l182'] = 182; + echo $b['l182']; + $b = $a; + $b['l183'] = 183; + echo $b['l183']; + $b = $a; + $b['l184'] = 184; + echo $b['l184']; + $b = $a; + $b['l185'] = 185; + echo $b['l185']; + $b = $a; + $b['l186'] = 186; + echo $b['l186']; + $b = $a; + $b['l187'] = 187; + echo $b['l187']; + $b = $a; + $b['l188'] = 188; + echo $b['l188']; + $b = $a; + $b['l189'] = 189; + echo $b['l189']; + $b = $a; + $b['l190'] = 190; + echo $b['l190']; + $b = $a; + $b['l191'] = 191; + echo $b['l191']; + $b = $a; + $b['l192'] = 192; + echo $b['l192']; + $b = $a; + $b['l193'] = 193; + echo $b['l193']; + $b = $a; + $b['l194'] = 194; + echo $b['l194']; + $b = $a; + $b['l195'] = 195; + echo $b['l195']; + $b = $a; + $b['l196'] = 196; + echo $b['l196']; + $b = $a; + $b['l197'] = 197; + echo $b['l197']; + $b = $a; + $b['l198'] = 198; + echo $b['l198']; + $b = $a; + $b['l199'] = 199; + echo $b['l199']; + $b = $a; + $b['l200'] = 200; + echo $b['l200']; + $b = $a; + $b['l201'] = 201; + echo $b['l201']; + $b = $a; + $b['l202'] = 202; + echo $b['l202']; + $b = $a; + $b['l203'] = 203; + echo $b['l203']; + $b = $a; + $b['l204'] = 204; + echo $b['l204']; + $b = $a; + $b['l205'] = 205; + echo $b['l205']; + $b = $a; + $b['l206'] = 206; + echo $b['l206']; + $b = $a; + $b['l207'] = 207; + echo $b['l207']; + $b = $a; + $b['l208'] = 208; + echo $b['l208']; + $b = $a; + $b['l209'] = 209; + echo $b['l209']; + $b = $a; + $b['l210'] = 210; + echo $b['l210']; + $b = $a; + $b['l211'] = 211; + echo $b['l211']; + $b = $a; + $b['l212'] = 212; + echo $b['l212']; + $b = $a; + $b['l213'] = 213; + echo $b['l213']; + $b = $a; + $b['l214'] = 214; + echo $b['l214']; + $b = $a; + $b['l215'] = 215; + echo $b['l215']; + $b = $a; + $b['l216'] = 216; + echo $b['l216']; + $b = $a; + $b['l217'] = 217; + echo $b['l217']; + $b = $a; + $b['l218'] = 218; + echo $b['l218']; + $b = $a; + $b['l219'] = 219; + echo $b['l219']; + $b = $a; + $b['l220'] = 220; + echo $b['l220']; + $b = $a; + $b['l221'] = 221; + echo $b['l221']; + $b = $a; + $b['l222'] = 222; + echo $b['l222']; + $b = $a; + $b['l223'] = 223; + echo $b['l223']; + $b = $a; + $b['l224'] = 224; + echo $b['l224']; + $b = $a; + $b['l225'] = 225; + echo $b['l225']; + $b = $a; + $b['l226'] = 226; + echo $b['l226']; + $b = $a; + $b['l227'] = 227; + echo $b['l227']; + $b = $a; + $b['l228'] = 228; + echo $b['l228']; + $b = $a; + $b['l229'] = 229; + echo $b['l229']; + $b = $a; + $b['l230'] = 230; + echo $b['l230']; + $b = $a; + $b['l231'] = 231; + echo $b['l231']; + $b = $a; + $b['l232'] = 232; + echo $b['l232']; + $b = $a; + $b['l233'] = 233; + echo $b['l233']; + $b = $a; + $b['l234'] = 234; + echo $b['l234']; + $b = $a; + $b['l235'] = 235; + echo $b['l235']; + $b = $a; + $b['l236'] = 236; + echo $b['l236']; + $b = $a; + $b['l237'] = 237; + echo $b['l237']; + $b = $a; + $b['l238'] = 238; + echo $b['l238']; + $b = $a; + $b['l239'] = 239; + echo $b['l239']; + $b = $a; + $b['l240'] = 240; + echo $b['l240']; + $b = $a; + $b['l241'] = 241; + echo $b['l241']; + $b = $a; + $b['l242'] = 242; + echo $b['l242']; + $b = $a; + $b['l243'] = 243; + echo $b['l243']; + $b = $a; + $b['l244'] = 244; + echo $b['l244']; + $b = $a; + $b['l245'] = 245; + echo $b['l245']; + $b = $a; + $b['l246'] = 246; + echo $b['l246']; + $b = $a; + $b['l247'] = 247; + echo $b['l247']; + $b = $a; + $b['l248'] = 248; + echo $b['l248']; + $b = $a; + $b['l249'] = 249; + echo $b['l249']; + $b = $a; + $b['l250'] = 250; + echo $b['l250']; + $b = $a; + $b['l251'] = 251; + echo $b['l251']; + $b = $a; + $b['l252'] = 252; + echo $b['l252']; + $b = $a; + $b['l253'] = 253; + echo $b['l253']; + $b = $a; + $b['l254'] = 254; + echo $b['l254']; + $b = $a; + $b['l255'] = 255; + echo $b['l255']; + $b = $a; + $b['l256'] = 256; + echo $b['l256']; + $b = $a; + $b['l257'] = 257; + echo $b['l257']; + $b = $a; + $b['l258'] = 258; + echo $b['l258']; + $b = $a; + $b['l259'] = 259; + echo $b['l259']; + $b = $a; + $b['l260'] = 260; + echo $b['l260']; + $b = $a; + $b['l261'] = 261; + echo $b['l261']; + $b = $a; + $b['l262'] = 262; + echo $b['l262']; + $b = $a; + $b['l263'] = 263; + echo $b['l263']; + $b = $a; + $b['l264'] = 264; + echo $b['l264']; + $b = $a; + $b['l265'] = 265; + echo $b['l265']; + $b = $a; + $b['l266'] = 266; + echo $b['l266']; + $b = $a; + $b['l267'] = 267; + echo $b['l267']; + $b = $a; + $b['l268'] = 268; + echo $b['l268']; + $b = $a; + $b['l269'] = 269; + echo $b['l269']; + $b = $a; + $b['l270'] = 270; + echo $b['l270']; + $b = $a; + $b['l271'] = 271; + echo $b['l271']; + $b = $a; + $b['l272'] = 272; + echo $b['l272']; + $b = $a; + $b['l273'] = 273; + echo $b['l273']; + $b = $a; + $b['l274'] = 274; + echo $b['l274']; + $b = $a; + $b['l275'] = 275; + echo $b['l275']; + $b = $a; + $b['l276'] = 276; + echo $b['l276']; + $b = $a; + $b['l277'] = 277; + echo $b['l277']; + $b = $a; + $b['l278'] = 278; + echo $b['l278']; + $b = $a; + $b['l279'] = 279; + echo $b['l279']; + $b = $a; + $b['l280'] = 280; + echo $b['l280']; + $b = $a; + $b['l281'] = 281; + echo $b['l281']; + $b = $a; + $b['l282'] = 282; + echo $b['l282']; + $b = $a; + $b['l283'] = 283; + echo $b['l283']; + $b = $a; + $b['l284'] = 284; + echo $b['l284']; + $b = $a; + $b['l285'] = 285; + echo $b['l285']; + $b = $a; + $b['l286'] = 286; + echo $b['l286']; + $b = $a; + $b['l287'] = 287; + echo $b['l287']; + $b = $a; + $b['l288'] = 288; + echo $b['l288']; + $b = $a; + $b['l289'] = 289; + echo $b['l289']; + $b = $a; + $b['l290'] = 290; + echo $b['l290']; + $b = $a; + $b['l291'] = 291; + echo $b['l291']; + $b = $a; + $b['l292'] = 292; + echo $b['l292']; + $b = $a; + $b['l293'] = 293; + echo $b['l293']; + $b = $a; + $b['l294'] = 294; + echo $b['l294']; + $b = $a; + $b['l295'] = 295; + echo $b['l295']; + $b = $a; + $b['l296'] = 296; + echo $b['l296']; + $b = $a; + $b['l297'] = 297; + echo $b['l297']; + $b = $a; + $b['l298'] = 298; + echo $b['l298']; + $b = $a; + $b['l299'] = 299; + echo $b['l299']; + $b = $a; + $b['l300'] = 300; + echo $b['l300']; + $b = $a; + $b['l301'] = 301; + echo $b['l301']; + $b = $a; + $b['l302'] = 302; + echo $b['l302']; + $b = $a; + $b['l303'] = 303; + echo $b['l303']; + $b = $a; + $b['l304'] = 304; + echo $b['l304']; + $b = $a; + $b['l305'] = 305; + echo $b['l305']; + $b = $a; + $b['l306'] = 306; + echo $b['l306']; + $b = $a; + $b['l307'] = 307; + echo $b['l307']; + $b = $a; + $b['l308'] = 308; + echo $b['l308']; + $b = $a; + $b['l309'] = 309; + echo $b['l309']; + $b = $a; + $b['l310'] = 310; + echo $b['l310']; + $b = $a; + $b['l311'] = 311; + echo $b['l311']; + $b = $a; + $b['l312'] = 312; + echo $b['l312']; + $b = $a; + $b['l313'] = 313; + echo $b['l313']; + $b = $a; + $b['l314'] = 314; + echo $b['l314']; + $b = $a; + $b['l315'] = 315; + echo $b['l315']; + $b = $a; + $b['l316'] = 316; + echo $b['l316']; + $b = $a; + $b['l317'] = 317; + echo $b['l317']; + $b = $a; + $b['l318'] = 318; + echo $b['l318']; + $b = $a; + $b['l319'] = 319; + echo $b['l319']; + $b = $a; + $b['l320'] = 320; + echo $b['l320']; + $b = $a; + $b['l321'] = 321; + echo $b['l321']; + $b = $a; + $b['l322'] = 322; + echo $b['l322']; + $b = $a; + $b['l323'] = 323; + echo $b['l323']; + $b = $a; + $b['l324'] = 324; + echo $b['l324']; + $b = $a; + $b['l325'] = 325; + echo $b['l325']; + $b = $a; + $b['l326'] = 326; + echo $b['l326']; + $b = $a; + $b['l327'] = 327; + echo $b['l327']; + $b = $a; + $b['l328'] = 328; + echo $b['l328']; + $b = $a; + $b['l329'] = 329; + echo $b['l329']; + $b = $a; + $b['l330'] = 330; + echo $b['l330']; + $b = $a; + $b['l331'] = 331; + echo $b['l331']; + $b = $a; + $b['l332'] = 332; + echo $b['l332']; + $b = $a; + $b['l333'] = 333; + echo $b['l333']; + $b = $a; + $b['l334'] = 334; + echo $b['l334']; + $b = $a; + $b['l335'] = 335; + echo $b['l335']; + $b = $a; + $b['l336'] = 336; + echo $b['l336']; + $b = $a; + $b['l337'] = 337; + echo $b['l337']; + $b = $a; + $b['l338'] = 338; + echo $b['l338']; + $b = $a; + $b['l339'] = 339; + echo $b['l339']; + $b = $a; + $b['l340'] = 340; + echo $b['l340']; + $b = $a; + $b['l341'] = 341; + echo $b['l341']; + $b = $a; + $b['l342'] = 342; + echo $b['l342']; + $b = $a; + $b['l343'] = 343; + echo $b['l343']; + $b = $a; + $b['l344'] = 344; + echo $b['l344']; + $b = $a; + $b['l345'] = 345; + echo $b['l345']; + $b = $a; + $b['l346'] = 346; + echo $b['l346']; + $b = $a; + $b['l347'] = 347; + echo $b['l347']; + $b = $a; + $b['l348'] = 348; + echo $b['l348']; + $b = $a; + $b['l349'] = 349; + echo $b['l349']; + $b = $a; + $b['l350'] = 350; + echo $b['l350']; + $b = $a; + $b['l351'] = 351; + echo $b['l351']; + $b = $a; + $b['l352'] = 352; + echo $b['l352']; + $b = $a; + $b['l353'] = 353; + echo $b['l353']; + $b = $a; + $b['l354'] = 354; + echo $b['l354']; + $b = $a; + $b['l355'] = 355; + echo $b['l355']; + $b = $a; + $b['l356'] = 356; + echo $b['l356']; + $b = $a; + $b['l357'] = 357; + echo $b['l357']; + $b = $a; + $b['l358'] = 358; + echo $b['l358']; + $b = $a; + $b['l359'] = 359; + echo $b['l359']; + $b = $a; + $b['l360'] = 360; + echo $b['l360']; + $b = $a; + $b['l361'] = 361; + echo $b['l361']; + $b = $a; + $b['l362'] = 362; + echo $b['l362']; + $b = $a; + $b['l363'] = 363; + echo $b['l363']; + $b = $a; + $b['l364'] = 364; + echo $b['l364']; + $b = $a; + $b['l365'] = 365; + echo $b['l365']; + $b = $a; + $b['l366'] = 366; + echo $b['l366']; + $b = $a; + $b['l367'] = 367; + echo $b['l367']; + $b = $a; + $b['l368'] = 368; + echo $b['l368']; + $b = $a; + $b['l369'] = 369; + echo $b['l369']; + $b = $a; + $b['l370'] = 370; + echo $b['l370']; + $b = $a; + $b['l371'] = 371; + echo $b['l371']; + $b = $a; + $b['l372'] = 372; + echo $b['l372']; + $b = $a; + $b['l373'] = 373; + echo $b['l373']; + $b = $a; + $b['l374'] = 374; + echo $b['l374']; + $b = $a; + $b['l375'] = 375; + echo $b['l375']; + $b = $a; + $b['l376'] = 376; + echo $b['l376']; + $b = $a; + $b['l377'] = 377; + echo $b['l377']; + $b = $a; + $b['l378'] = 378; + echo $b['l378']; + $b = $a; + $b['l379'] = 379; + echo $b['l379']; + $b = $a; + $b['l380'] = 380; + echo $b['l380']; + $b = $a; + $b['l381'] = 381; + echo $b['l381']; + $b = $a; + $b['l382'] = 382; + echo $b['l382']; + $b = $a; + $b['l383'] = 383; + echo $b['l383']; + $b = $a; + $b['l384'] = 384; + echo $b['l384']; + $b = $a; + $b['l385'] = 385; + echo $b['l385']; + $b = $a; + $b['l386'] = 386; + echo $b['l386']; + $b = $a; + $b['l387'] = 387; + echo $b['l387']; + $b = $a; + $b['l388'] = 388; + echo $b['l388']; + $b = $a; + $b['l389'] = 389; + echo $b['l389']; + $b = $a; + $b['l390'] = 390; + echo $b['l390']; + $b = $a; + $b['l391'] = 391; + echo $b['l391']; + $b = $a; + $b['l392'] = 392; + echo $b['l392']; + $b = $a; + $b['l393'] = 393; + echo $b['l393']; + $b = $a; + $b['l394'] = 394; + echo $b['l394']; + $b = $a; + $b['l395'] = 395; + echo $b['l395']; + $b = $a; + $b['l396'] = 396; + echo $b['l396']; + $b = $a; + $b['l397'] = 397; + echo $b['l397']; + $b = $a; + $b['l398'] = 398; + echo $b['l398']; + $b = $a; + $b['l399'] = 399; + echo $b['l399']; + $b = $a; + $b['l400'] = 400; + echo $b['l400']; + $b = $a; + $b['l401'] = 401; + echo $b['l401']; + $b = $a; + $b['l402'] = 402; + echo $b['l402']; + $b = $a; + $b['l403'] = 403; + echo $b['l403']; + $b = $a; + $b['l404'] = 404; + echo $b['l404']; + $b = $a; + $b['l405'] = 405; + echo $b['l405']; + $b = $a; + $b['l406'] = 406; + echo $b['l406']; + $b = $a; + $b['l407'] = 407; + echo $b['l407']; + $b = $a; + $b['l408'] = 408; + echo $b['l408']; + $b = $a; + $b['l409'] = 409; + echo $b['l409']; + $b = $a; + $b['l410'] = 410; + echo $b['l410']; + $b = $a; + $b['l411'] = 411; + echo $b['l411']; + $b = $a; + $b['l412'] = 412; + echo $b['l412']; + $b = $a; + $b['l413'] = 413; + echo $b['l413']; + $b = $a; + $b['l414'] = 414; + echo $b['l414']; + $b = $a; + $b['l415'] = 415; + echo $b['l415']; + $b = $a; + $b['l416'] = 416; + echo $b['l416']; + $b = $a; + $b['l417'] = 417; + echo $b['l417']; + $b = $a; + $b['l418'] = 418; + echo $b['l418']; + $b = $a; + $b['l419'] = 419; + echo $b['l419']; + $b = $a; + $b['l420'] = 420; + echo $b['l420']; + $b = $a; + $b['l421'] = 421; + echo $b['l421']; + $b = $a; + $b['l422'] = 422; + echo $b['l422']; + $b = $a; + $b['l423'] = 423; + echo $b['l423']; + $b = $a; + $b['l424'] = 424; + echo $b['l424']; + $b = $a; + $b['l425'] = 425; + echo $b['l425']; + $b = $a; + $b['l426'] = 426; + echo $b['l426']; + $b = $a; + $b['l427'] = 427; + echo $b['l427']; + $b = $a; + $b['l428'] = 428; + echo $b['l428']; + $b = $a; + $b['l429'] = 429; + echo $b['l429']; + $b = $a; + $b['l430'] = 430; + echo $b['l430']; + $b = $a; + $b['l431'] = 431; + echo $b['l431']; + $b = $a; + $b['l432'] = 432; + echo $b['l432']; + $b = $a; + $b['l433'] = 433; + echo $b['l433']; + $b = $a; + $b['l434'] = 434; + echo $b['l434']; + $b = $a; + $b['l435'] = 435; + echo $b['l435']; + $b = $a; + $b['l436'] = 436; + echo $b['l436']; + $b = $a; + $b['l437'] = 437; + echo $b['l437']; + $b = $a; + $b['l438'] = 438; + echo $b['l438']; + $b = $a; + $b['l439'] = 439; + echo $b['l439']; + $b = $a; + $b['l440'] = 440; + echo $b['l440']; + $b = $a; + $b['l441'] = 441; + echo $b['l441']; + $b = $a; + $b['l442'] = 442; + echo $b['l442']; + $b = $a; + $b['l443'] = 443; + echo $b['l443']; + $b = $a; + $b['l444'] = 444; + echo $b['l444']; + $b = $a; + $b['l445'] = 445; + echo $b['l445']; + $b = $a; + $b['l446'] = 446; + echo $b['l446']; + $b = $a; + $b['l447'] = 447; + echo $b['l447']; + $b = $a; + $b['l448'] = 448; + echo $b['l448']; + $b = $a; + $b['l449'] = 449; + echo $b['l449']; + $b = $a; + $b['l450'] = 450; + echo $b['l450']; + $b = $a; + $b['l451'] = 451; + echo $b['l451']; + $b = $a; + $b['l452'] = 452; + echo $b['l452']; + $b = $a; + $b['l453'] = 453; + echo $b['l453']; + $b = $a; + $b['l454'] = 454; + echo $b['l454']; + $b = $a; + $b['l455'] = 455; + echo $b['l455']; + $b = $a; + $b['l456'] = 456; + echo $b['l456']; + $b = $a; + $b['l457'] = 457; + echo $b['l457']; + $b = $a; + $b['l458'] = 458; + echo $b['l458']; + $b = $a; + $b['l459'] = 459; + echo $b['l459']; + $b = $a; + $b['l460'] = 460; + echo $b['l460']; + $b = $a; + $b['l461'] = 461; + echo $b['l461']; + $b = $a; + $b['l462'] = 462; + echo $b['l462']; + $b = $a; + $b['l463'] = 463; + echo $b['l463']; + $b = $a; + $b['l464'] = 464; + echo $b['l464']; + $b = $a; + $b['l465'] = 465; + echo $b['l465']; + $b = $a; + $b['l466'] = 466; + echo $b['l466']; + $b = $a; + $b['l467'] = 467; + echo $b['l467']; + $b = $a; + $b['l468'] = 468; + echo $b['l468']; + $b = $a; + $b['l469'] = 469; + echo $b['l469']; + $b = $a; + $b['l470'] = 470; + echo $b['l470']; + $b = $a; + $b['l471'] = 471; + echo $b['l471']; + $b = $a; + $b['l472'] = 472; + echo $b['l472']; + $b = $a; + $b['l473'] = 473; + echo $b['l473']; + $b = $a; + $b['l474'] = 474; + echo $b['l474']; + $b = $a; + $b['l475'] = 475; + echo $b['l475']; + $b = $a; + $b['l476'] = 476; + echo $b['l476']; + $b = $a; + $b['l477'] = 477; + echo $b['l477']; + $b = $a; + $b['l478'] = 478; + echo $b['l478']; + $b = $a; + $b['l479'] = 479; + echo $b['l479']; + $b = $a; + $b['l480'] = 480; + echo $b['l480']; + $b = $a; + $b['l481'] = 481; + echo $b['l481']; + $b = $a; + $b['l482'] = 482; + echo $b['l482']; + $b = $a; + $b['l483'] = 483; + echo $b['l483']; + $b = $a; + $b['l484'] = 484; + echo $b['l484']; + $b = $a; + $b['l485'] = 485; + echo $b['l485']; + $b = $a; + $b['l486'] = 486; + echo $b['l486']; + $b = $a; + $b['l487'] = 487; + echo $b['l487']; + $b = $a; + $b['l488'] = 488; + echo $b['l488']; + $b = $a; + $b['l489'] = 489; + echo $b['l489']; + $b = $a; + $b['l490'] = 490; + echo $b['l490']; + $b = $a; + $b['l491'] = 491; + echo $b['l491']; + $b = $a; + $b['l492'] = 492; + echo $b['l492']; + $b = $a; + $b['l493'] = 493; + echo $b['l493']; + $b = $a; + $b['l494'] = 494; + echo $b['l494']; + $b = $a; + $b['l495'] = 495; + echo $b['l495']; + $b = $a; + $b['l496'] = 496; + echo $b['l496']; + $b = $a; + $b['l497'] = 497; + echo $b['l497']; + $b = $a; + $b['l498'] = 498; + echo $b['l498']; + $b = $a; + $b['l499'] = 499; + echo $b['l499']; + $b = $a; + $b['l500'] = 500; + echo $b['l500']; + $b = $a; + $b['l501'] = 501; + echo $b['l501']; + $b = $a; + $b['l502'] = 502; + echo $b['l502']; + $b = $a; + $b['l503'] = 503; + echo $b['l503']; + $b = $a; + $b['l504'] = 504; + echo $b['l504']; + $b = $a; + $b['l505'] = 505; + echo $b['l505']; + $b = $a; + $b['l506'] = 506; + echo $b['l506']; + $b = $a; + $b['l507'] = 507; + echo $b['l507']; + $b = $a; + $b['l508'] = 508; + echo $b['l508']; + $b = $a; + $b['l509'] = 509; + echo $b['l509']; + $b = $a; + $b['l510'] = 510; + echo $b['l510']; + $b = $a; + $b['l511'] = 511; + echo $b['l511']; + $b = $a; + $b['l512'] = 512; + echo $b['l512']; + $b = $a; + $b['l513'] = 513; + echo $b['l513']; + $b = $a; + $b['l514'] = 514; + echo $b['l514']; + $b = $a; + $b['l515'] = 515; + echo $b['l515']; + $b = $a; + $b['l516'] = 516; + echo $b['l516']; + $b = $a; + $b['l517'] = 517; + echo $b['l517']; + $b = $a; + $b['l518'] = 518; + echo $b['l518']; + $b = $a; + $b['l519'] = 519; + echo $b['l519']; + $b = $a; + $b['l520'] = 520; + echo $b['l520']; + $b = $a; + $b['l521'] = 521; + echo $b['l521']; + $b = $a; + $b['l522'] = 522; + echo $b['l522']; + $b = $a; + $b['l523'] = 523; + echo $b['l523']; + $b = $a; + $b['l524'] = 524; + echo $b['l524']; + $b = $a; + $b['l525'] = 525; + echo $b['l525']; + $b = $a; + $b['l526'] = 526; + echo $b['l526']; + $b = $a; + $b['l527'] = 527; + echo $b['l527']; + $b = $a; + $b['l528'] = 528; + echo $b['l528']; + $b = $a; + $b['l529'] = 529; + echo $b['l529']; + $b = $a; + $b['l530'] = 530; + echo $b['l530']; + $b = $a; + $b['l531'] = 531; + echo $b['l531']; + $b = $a; + $b['l532'] = 532; + echo $b['l532']; + $b = $a; + $b['l533'] = 533; + echo $b['l533']; + $b = $a; + $b['l534'] = 534; + echo $b['l534']; + $b = $a; + $b['l535'] = 535; + echo $b['l535']; + $b = $a; + $b['l536'] = 536; + echo $b['l536']; + $b = $a; + $b['l537'] = 537; + echo $b['l537']; + $b = $a; + $b['l538'] = 538; + echo $b['l538']; + $b = $a; + $b['l539'] = 539; + echo $b['l539']; + $b = $a; + $b['l540'] = 540; + echo $b['l540']; + $b = $a; + $b['l541'] = 541; + echo $b['l541']; + $b = $a; + $b['l542'] = 542; + echo $b['l542']; + $b = $a; + $b['l543'] = 543; + echo $b['l543']; + $b = $a; + $b['l544'] = 544; + echo $b['l544']; + $b = $a; + $b['l545'] = 545; + echo $b['l545']; + $b = $a; + $b['l546'] = 546; + echo $b['l546']; + $b = $a; + $b['l547'] = 547; + echo $b['l547']; + $b = $a; + $b['l548'] = 548; + echo $b['l548']; + $b = $a; + $b['l549'] = 549; + echo $b['l549']; + $b = $a; + $b['l550'] = 550; + echo $b['l550']; + $b = $a; + $b['l551'] = 551; + echo $b['l551']; + $b = $a; + $b['l552'] = 552; + echo $b['l552']; + $b = $a; + $b['l553'] = 553; + echo $b['l553']; + $b = $a; + $b['l554'] = 554; + echo $b['l554']; + $b = $a; + $b['l555'] = 555; + echo $b['l555']; + $b = $a; + $b['l556'] = 556; + echo $b['l556']; + $b = $a; + $b['l557'] = 557; + echo $b['l557']; + $b = $a; + $b['l558'] = 558; + echo $b['l558']; + $b = $a; + $b['l559'] = 559; + echo $b['l559']; + $b = $a; + $b['l560'] = 560; + echo $b['l560']; + $b = $a; + $b['l561'] = 561; + echo $b['l561']; + $b = $a; + $b['l562'] = 562; + echo $b['l562']; + $b = $a; + $b['l563'] = 563; + echo $b['l563']; + $b = $a; + $b['l564'] = 564; + echo $b['l564']; + $b = $a; + $b['l565'] = 565; + echo $b['l565']; + $b = $a; + $b['l566'] = 566; + echo $b['l566']; + $b = $a; + $b['l567'] = 567; + echo $b['l567']; + $b = $a; + $b['l568'] = 568; + echo $b['l568']; + $b = $a; + $b['l569'] = 569; + echo $b['l569']; + $b = $a; + $b['l570'] = 570; + echo $b['l570']; + $b = $a; + $b['l571'] = 571; + echo $b['l571']; + $b = $a; + $b['l572'] = 572; + echo $b['l572']; + $b = $a; + $b['l573'] = 573; + echo $b['l573']; + $b = $a; + $b['l574'] = 574; + echo $b['l574']; + $b = $a; + $b['l575'] = 575; + echo $b['l575']; + $b = $a; + $b['l576'] = 576; + echo $b['l576']; + $b = $a; + $b['l577'] = 577; + echo $b['l577']; + $b = $a; + $b['l578'] = 578; + echo $b['l578']; + $b = $a; + $b['l579'] = 579; + echo $b['l579']; + $b = $a; + $b['l580'] = 580; + echo $b['l580']; + $b = $a; + $b['l581'] = 581; + echo $b['l581']; + $b = $a; + $b['l582'] = 582; + echo $b['l582']; + $b = $a; + $b['l583'] = 583; + echo $b['l583']; + $b = $a; + $b['l584'] = 584; + echo $b['l584']; + $b = $a; + $b['l585'] = 585; + echo $b['l585']; + $b = $a; + $b['l586'] = 586; + echo $b['l586']; + $b = $a; + $b['l587'] = 587; + echo $b['l587']; + $b = $a; + $b['l588'] = 588; + echo $b['l588']; + $b = $a; + $b['l589'] = 589; + echo $b['l589']; + $b = $a; + $b['l590'] = 590; + echo $b['l590']; + $b = $a; + $b['l591'] = 591; + echo $b['l591']; + $b = $a; + $b['l592'] = 592; + echo $b['l592']; + $b = $a; + $b['l593'] = 593; + echo $b['l593']; + $b = $a; + $b['l594'] = 594; + echo $b['l594']; + $b = $a; + $b['l595'] = 595; + echo $b['l595']; + $b = $a; + $b['l596'] = 596; + echo $b['l596']; + $b = $a; + $b['l597'] = 597; + echo $b['l597']; + $b = $a; + $b['l598'] = 598; + echo $b['l598']; + $b = $a; + $b['l599'] = 599; + echo $b['l599']; + $b = $a; + $b['l600'] = 600; + echo $b['l600']; + $b = $a; + $b['l601'] = 601; + echo $b['l601']; + $b = $a; + $b['l602'] = 602; + echo $b['l602']; + $b = $a; + $b['l603'] = 603; + echo $b['l603']; + $b = $a; + $b['l604'] = 604; + echo $b['l604']; + $b = $a; + $b['l605'] = 605; + echo $b['l605']; + $b = $a; + $b['l606'] = 606; + echo $b['l606']; + $b = $a; + $b['l607'] = 607; + echo $b['l607']; + $b = $a; + $b['l608'] = 608; + echo $b['l608']; + $b = $a; + $b['l609'] = 609; + echo $b['l609']; + $b = $a; + $b['l610'] = 610; + echo $b['l610']; + $b = $a; + $b['l611'] = 611; + echo $b['l611']; + $b = $a; + $b['l612'] = 612; + echo $b['l612']; + $b = $a; + $b['l613'] = 613; + echo $b['l613']; + $b = $a; + $b['l614'] = 614; + echo $b['l614']; + $b = $a; + $b['l615'] = 615; + echo $b['l615']; + $b = $a; + $b['l616'] = 616; + echo $b['l616']; + $b = $a; + $b['l617'] = 617; + echo $b['l617']; + $b = $a; + $b['l618'] = 618; + echo $b['l618']; + $b = $a; + $b['l619'] = 619; + echo $b['l619']; + $b = $a; + $b['l620'] = 620; + echo $b['l620']; + $b = $a; + $b['l621'] = 621; + echo $b['l621']; + $b = $a; + $b['l622'] = 622; + echo $b['l622']; + $b = $a; + $b['l623'] = 623; + echo $b['l623']; + $b = $a; + $b['l624'] = 624; + echo $b['l624']; + $b = $a; + $b['l625'] = 625; + echo $b['l625']; + $b = $a; + $b['l626'] = 626; + echo $b['l626']; + $b = $a; + $b['l627'] = 627; + echo $b['l627']; + $b = $a; + $b['l628'] = 628; + echo $b['l628']; + $b = $a; + $b['l629'] = 629; + echo $b['l629']; + $b = $a; + $b['l630'] = 630; + echo $b['l630']; + $b = $a; + $b['l631'] = 631; + echo $b['l631']; + $b = $a; + $b['l632'] = 632; + echo $b['l632']; + $b = $a; + $b['l633'] = 633; + echo $b['l633']; + $b = $a; + $b['l634'] = 634; + echo $b['l634']; + $b = $a; + $b['l635'] = 635; + echo $b['l635']; + $b = $a; + $b['l636'] = 636; + echo $b['l636']; + $b = $a; + $b['l637'] = 637; + echo $b['l637']; + $b = $a; + $b['l638'] = 638; + echo $b['l638']; + $b = $a; + $b['l639'] = 639; + echo $b['l639']; + $b = $a; + $b['l640'] = 640; + echo $b['l640']; + $b = $a; + $b['l641'] = 641; + echo $b['l641']; + $b = $a; + $b['l642'] = 642; + echo $b['l642']; + $b = $a; + $b['l643'] = 643; + echo $b['l643']; + $b = $a; + $b['l644'] = 644; + echo $b['l644']; + $b = $a; + $b['l645'] = 645; + echo $b['l645']; + $b = $a; + $b['l646'] = 646; + echo $b['l646']; + $b = $a; + $b['l647'] = 647; + echo $b['l647']; + $b = $a; + $b['l648'] = 648; + echo $b['l648']; + $b = $a; + $b['l649'] = 649; + echo $b['l649']; + $b = $a; + $b['l650'] = 650; + echo $b['l650']; + $b = $a; + $b['l651'] = 651; + echo $b['l651']; + $b = $a; + $b['l652'] = 652; + echo $b['l652']; + $b = $a; + $b['l653'] = 653; + echo $b['l653']; + $b = $a; + $b['l654'] = 654; + echo $b['l654']; + $b = $a; + $b['l655'] = 655; + echo $b['l655']; + $b = $a; + $b['l656'] = 656; + echo $b['l656']; + $b = $a; + $b['l657'] = 657; + echo $b['l657']; + $b = $a; + $b['l658'] = 658; + echo $b['l658']; + $b = $a; + $b['l659'] = 659; + echo $b['l659']; + $b = $a; + $b['l660'] = 660; + echo $b['l660']; + $b = $a; + $b['l661'] = 661; + echo $b['l661']; + $b = $a; + $b['l662'] = 662; + echo $b['l662']; + $b = $a; + $b['l663'] = 663; + echo $b['l663']; + $b = $a; + $b['l664'] = 664; + echo $b['l664']; + $b = $a; + $b['l665'] = 665; + echo $b['l665']; + $b = $a; + $b['l666'] = 666; + echo $b['l666']; + $b = $a; + $b['l667'] = 667; + echo $b['l667']; + $b = $a; + $b['l668'] = 668; + echo $b['l668']; + $b = $a; + $b['l669'] = 669; + echo $b['l669']; + $b = $a; + $b['l670'] = 670; + echo $b['l670']; + $b = $a; + $b['l671'] = 671; + echo $b['l671']; + $b = $a; + $b['l672'] = 672; + echo $b['l672']; + $b = $a; + $b['l673'] = 673; + echo $b['l673']; + $b = $a; + $b['l674'] = 674; + echo $b['l674']; + $b = $a; + $b['l675'] = 675; + echo $b['l675']; + $b = $a; + $b['l676'] = 676; + echo $b['l676']; + $b = $a; + $b['l677'] = 677; + echo $b['l677']; + $b = $a; + $b['l678'] = 678; + echo $b['l678']; + $b = $a; + $b['l679'] = 679; + echo $b['l679']; + $b = $a; + $b['l680'] = 680; + echo $b['l680']; + $b = $a; + $b['l681'] = 681; + echo $b['l681']; + $b = $a; + $b['l682'] = 682; + echo $b['l682']; + $b = $a; + $b['l683'] = 683; + echo $b['l683']; + $b = $a; + $b['l684'] = 684; + echo $b['l684']; + $b = $a; + $b['l685'] = 685; + echo $b['l685']; + $b = $a; + $b['l686'] = 686; + echo $b['l686']; + $b = $a; + $b['l687'] = 687; + echo $b['l687']; + $b = $a; + $b['l688'] = 688; + echo $b['l688']; + $b = $a; + $b['l689'] = 689; + echo $b['l689']; + $b = $a; + $b['l690'] = 690; + echo $b['l690']; + $b = $a; + $b['l691'] = 691; + echo $b['l691']; + $b = $a; + $b['l692'] = 692; + echo $b['l692']; + $b = $a; + $b['l693'] = 693; + echo $b['l693']; + $b = $a; + $b['l694'] = 694; + echo $b['l694']; + $b = $a; + $b['l695'] = 695; + echo $b['l695']; + $b = $a; + $b['l696'] = 696; + echo $b['l696']; + $b = $a; + $b['l697'] = 697; + echo $b['l697']; + $b = $a; + $b['l698'] = 698; + echo $b['l698']; + $b = $a; + $b['l699'] = 699; + echo $b['l699']; + $b = $a; + $b['l700'] = 700; + echo $b['l700']; + $b = $a; + $b['l701'] = 701; + echo $b['l701']; + $b = $a; + $b['l702'] = 702; + echo $b['l702']; + $b = $a; + $b['l703'] = 703; + echo $b['l703']; + $b = $a; + $b['l704'] = 704; + echo $b['l704']; + $b = $a; + $b['l705'] = 705; + echo $b['l705']; + $b = $a; + $b['l706'] = 706; + echo $b['l706']; + $b = $a; + $b['l707'] = 707; + echo $b['l707']; + $b = $a; + $b['l708'] = 708; + echo $b['l708']; + $b = $a; + $b['l709'] = 709; + echo $b['l709']; + $b = $a; + $b['l710'] = 710; + echo $b['l710']; + $b = $a; + $b['l711'] = 711; + echo $b['l711']; + $b = $a; + $b['l712'] = 712; + echo $b['l712']; + $b = $a; + $b['l713'] = 713; + echo $b['l713']; + $b = $a; + $b['l714'] = 714; + echo $b['l714']; + $b = $a; + $b['l715'] = 715; + echo $b['l715']; + $b = $a; + $b['l716'] = 716; + echo $b['l716']; + $b = $a; + $b['l717'] = 717; + echo $b['l717']; + $b = $a; + $b['l718'] = 718; + echo $b['l718']; + $b = $a; + $b['l719'] = 719; + echo $b['l719']; + $b = $a; + $b['l720'] = 720; + echo $b['l720']; + $b = $a; + $b['l721'] = 721; + echo $b['l721']; + $b = $a; + $b['l722'] = 722; + echo $b['l722']; + $b = $a; + $b['l723'] = 723; + echo $b['l723']; + $b = $a; + $b['l724'] = 724; + echo $b['l724']; + $b = $a; + $b['l725'] = 725; + echo $b['l725']; + $b = $a; + $b['l726'] = 726; + echo $b['l726']; + $b = $a; + $b['l727'] = 727; + echo $b['l727']; + $b = $a; + $b['l728'] = 728; + echo $b['l728']; + $b = $a; + $b['l729'] = 729; + echo $b['l729']; + $b = $a; + $b['l730'] = 730; + echo $b['l730']; + $b = $a; + $b['l731'] = 731; + echo $b['l731']; + $b = $a; + $b['l732'] = 732; + echo $b['l732']; + $b = $a; + $b['l733'] = 733; + echo $b['l733']; + $b = $a; + $b['l734'] = 734; + echo $b['l734']; + $b = $a; + $b['l735'] = 735; + echo $b['l735']; + $b = $a; + $b['l736'] = 736; + echo $b['l736']; + $b = $a; + $b['l737'] = 737; + echo $b['l737']; + $b = $a; + $b['l738'] = 738; + echo $b['l738']; + $b = $a; + $b['l739'] = 739; + echo $b['l739']; + $b = $a; + $b['l740'] = 740; + echo $b['l740']; + $b = $a; + $b['l741'] = 741; + echo $b['l741']; + $b = $a; + $b['l742'] = 742; + echo $b['l742']; + $b = $a; + $b['l743'] = 743; + echo $b['l743']; + $b = $a; + $b['l744'] = 744; + echo $b['l744']; + $b = $a; + $b['l745'] = 745; + echo $b['l745']; + $b = $a; + $b['l746'] = 746; + echo $b['l746']; + $b = $a; + $b['l747'] = 747; + echo $b['l747']; + $b = $a; + $b['l748'] = 748; + echo $b['l748']; + $b = $a; + $b['l749'] = 749; + echo $b['l749']; + $b = $a; + $b['l750'] = 750; + echo $b['l750']; + $b = $a; + $b['l751'] = 751; + echo $b['l751']; + $b = $a; + $b['l752'] = 752; + echo $b['l752']; + $b = $a; + $b['l753'] = 753; + echo $b['l753']; + $b = $a; + $b['l754'] = 754; + echo $b['l754']; + $b = $a; + $b['l755'] = 755; + echo $b['l755']; + $b = $a; + $b['l756'] = 756; + echo $b['l756']; + $b = $a; + $b['l757'] = 757; + echo $b['l757']; + $b = $a; + $b['l758'] = 758; + echo $b['l758']; + $b = $a; + $b['l759'] = 759; + echo $b['l759']; + $b = $a; + $b['l760'] = 760; + echo $b['l760']; + $b = $a; + $b['l761'] = 761; + echo $b['l761']; + $b = $a; + $b['l762'] = 762; + echo $b['l762']; + $b = $a; + $b['l763'] = 763; + echo $b['l763']; + $b = $a; + $b['l764'] = 764; + echo $b['l764']; + $b = $a; + $b['l765'] = 765; + echo $b['l765']; + $b = $a; + $b['l766'] = 766; + echo $b['l766']; + $b = $a; + $b['l767'] = 767; + echo $b['l767']; + $b = $a; + $b['l768'] = 768; + echo $b['l768']; + $b = $a; + $b['l769'] = 769; + echo $b['l769']; + $b = $a; + $b['l770'] = 770; + echo $b['l770']; + $b = $a; + $b['l771'] = 771; + echo $b['l771']; + $b = $a; + $b['l772'] = 772; + echo $b['l772']; + $b = $a; + $b['l773'] = 773; + echo $b['l773']; + $b = $a; + $b['l774'] = 774; + echo $b['l774']; + $b = $a; + $b['l775'] = 775; + echo $b['l775']; + $b = $a; + $b['l776'] = 776; + echo $b['l776']; + $b = $a; + $b['l777'] = 777; + echo $b['l777']; + $b = $a; + $b['l778'] = 778; + echo $b['l778']; + $b = $a; + $b['l779'] = 779; + echo $b['l779']; + $b = $a; + $b['l780'] = 780; + echo $b['l780']; + $b = $a; + $b['l781'] = 781; + echo $b['l781']; + $b = $a; + $b['l782'] = 782; + echo $b['l782']; + $b = $a; + $b['l783'] = 783; + echo $b['l783']; + $b = $a; + $b['l784'] = 784; + echo $b['l784']; + $b = $a; + $b['l785'] = 785; + echo $b['l785']; + $b = $a; + $b['l786'] = 786; + echo $b['l786']; + $b = $a; + $b['l787'] = 787; + echo $b['l787']; + $b = $a; + $b['l788'] = 788; + echo $b['l788']; + $b = $a; + $b['l789'] = 789; + echo $b['l789']; + $b = $a; + $b['l790'] = 790; + echo $b['l790']; + $b = $a; + $b['l791'] = 791; + echo $b['l791']; + $b = $a; + $b['l792'] = 792; + echo $b['l792']; + $b = $a; + $b['l793'] = 793; + echo $b['l793']; + $b = $a; + $b['l794'] = 794; + echo $b['l794']; + $b = $a; + $b['l795'] = 795; + echo $b['l795']; + $b = $a; + $b['l796'] = 796; + echo $b['l796']; + $b = $a; + $b['l797'] = 797; + echo $b['l797']; + $b = $a; + $b['l798'] = 798; + echo $b['l798']; + $b = $a; + $b['l799'] = 799; + echo $b['l799']; + $b = $a; + $b['l800'] = 800; + echo $b['l800']; + $b = $a; + $b['l801'] = 801; + echo $b['l801']; + $b = $a; + $b['l802'] = 802; + echo $b['l802']; + $b = $a; + $b['l803'] = 803; + echo $b['l803']; + $b = $a; + $b['l804'] = 804; + echo $b['l804']; + $b = $a; + $b['l805'] = 805; + echo $b['l805']; + $b = $a; + $b['l806'] = 806; + echo $b['l806']; + $b = $a; + $b['l807'] = 807; + echo $b['l807']; + $b = $a; + $b['l808'] = 808; + echo $b['l808']; + $b = $a; + $b['l809'] = 809; + echo $b['l809']; + $b = $a; + $b['l810'] = 810; + echo $b['l810']; + $b = $a; + $b['l811'] = 811; + echo $b['l811']; + $b = $a; + $b['l812'] = 812; + echo $b['l812']; + $b = $a; + $b['l813'] = 813; + echo $b['l813']; + $b = $a; + $b['l814'] = 814; + echo $b['l814']; + $b = $a; + $b['l815'] = 815; + echo $b['l815']; + $b = $a; + $b['l816'] = 816; + echo $b['l816']; + $b = $a; + $b['l817'] = 817; + echo $b['l817']; + $b = $a; + $b['l818'] = 818; + echo $b['l818']; + $b = $a; + $b['l819'] = 819; + echo $b['l819']; + $b = $a; + $b['l820'] = 820; + echo $b['l820']; + $b = $a; + $b['l821'] = 821; + echo $b['l821']; + $b = $a; + $b['l822'] = 822; + echo $b['l822']; + $b = $a; + $b['l823'] = 823; + echo $b['l823']; + $b = $a; + $b['l824'] = 824; + echo $b['l824']; + $b = $a; + $b['l825'] = 825; + echo $b['l825']; + $b = $a; + $b['l826'] = 826; + echo $b['l826']; + $b = $a; + $b['l827'] = 827; + echo $b['l827']; + $b = $a; + $b['l828'] = 828; + echo $b['l828']; + $b = $a; + $b['l829'] = 829; + echo $b['l829']; + $b = $a; + $b['l830'] = 830; + echo $b['l830']; + $b = $a; + $b['l831'] = 831; + echo $b['l831']; + $b = $a; + $b['l832'] = 832; + echo $b['l832']; + $b = $a; + $b['l833'] = 833; + echo $b['l833']; + $b = $a; + $b['l834'] = 834; + echo $b['l834']; + $b = $a; + $b['l835'] = 835; + echo $b['l835']; + $b = $a; + $b['l836'] = 836; + echo $b['l836']; + $b = $a; + $b['l837'] = 837; + echo $b['l837']; + $b = $a; + $b['l838'] = 838; + echo $b['l838']; + $b = $a; + $b['l839'] = 839; + echo $b['l839']; + $b = $a; + $b['l840'] = 840; + echo $b['l840']; + $b = $a; + $b['l841'] = 841; + echo $b['l841']; + $b = $a; + $b['l842'] = 842; + echo $b['l842']; + $b = $a; + $b['l843'] = 843; + echo $b['l843']; + $b = $a; + $b['l844'] = 844; + echo $b['l844']; + $b = $a; + $b['l845'] = 845; + echo $b['l845']; + $b = $a; + $b['l846'] = 846; + echo $b['l846']; + $b = $a; + $b['l847'] = 847; + echo $b['l847']; + $b = $a; + $b['l848'] = 848; + echo $b['l848']; + $b = $a; + $b['l849'] = 849; + echo $b['l849']; + $b = $a; + $b['l850'] = 850; + echo $b['l850']; + $b = $a; + $b['l851'] = 851; + echo $b['l851']; + $b = $a; + $b['l852'] = 852; + echo $b['l852']; + $b = $a; + $b['l853'] = 853; + echo $b['l853']; + $b = $a; + $b['l854'] = 854; + echo $b['l854']; + $b = $a; + $b['l855'] = 855; + echo $b['l855']; + $b = $a; + $b['l856'] = 856; + echo $b['l856']; + $b = $a; + $b['l857'] = 857; + echo $b['l857']; + $b = $a; + $b['l858'] = 858; + echo $b['l858']; + $b = $a; + $b['l859'] = 859; + echo $b['l859']; + $b = $a; + $b['l860'] = 860; + echo $b['l860']; + $b = $a; + $b['l861'] = 861; + echo $b['l861']; + $b = $a; + $b['l862'] = 862; + echo $b['l862']; + $b = $a; + $b['l863'] = 863; + echo $b['l863']; + $b = $a; + $b['l864'] = 864; + echo $b['l864']; + $b = $a; + $b['l865'] = 865; + echo $b['l865']; + $b = $a; + $b['l866'] = 866; + echo $b['l866']; + $b = $a; + $b['l867'] = 867; + echo $b['l867']; + $b = $a; + $b['l868'] = 868; + echo $b['l868']; + $b = $a; + $b['l869'] = 869; + echo $b['l869']; + $b = $a; + $b['l870'] = 870; + echo $b['l870']; + $b = $a; + $b['l871'] = 871; + echo $b['l871']; + $b = $a; + $b['l872'] = 872; + echo $b['l872']; + $b = $a; + $b['l873'] = 873; + echo $b['l873']; + $b = $a; + $b['l874'] = 874; + echo $b['l874']; + $b = $a; + $b['l875'] = 875; + echo $b['l875']; + $b = $a; + $b['l876'] = 876; + echo $b['l876']; + $b = $a; + $b['l877'] = 877; + echo $b['l877']; + $b = $a; + $b['l878'] = 878; + echo $b['l878']; + $b = $a; + $b['l879'] = 879; + echo $b['l879']; + $b = $a; + $b['l880'] = 880; + echo $b['l880']; + $b = $a; + $b['l881'] = 881; + echo $b['l881']; + $b = $a; + $b['l882'] = 882; + echo $b['l882']; + $b = $a; + $b['l883'] = 883; + echo $b['l883']; + $b = $a; + $b['l884'] = 884; + echo $b['l884']; + $b = $a; + $b['l885'] = 885; + echo $b['l885']; + $b = $a; + $b['l886'] = 886; + echo $b['l886']; + $b = $a; + $b['l887'] = 887; + echo $b['l887']; + $b = $a; + $b['l888'] = 888; + echo $b['l888']; + $b = $a; + $b['l889'] = 889; + echo $b['l889']; + $b = $a; + $b['l890'] = 890; + echo $b['l890']; + $b = $a; + $b['l891'] = 891; + echo $b['l891']; + $b = $a; + $b['l892'] = 892; + echo $b['l892']; + $b = $a; + $b['l893'] = 893; + echo $b['l893']; + $b = $a; + $b['l894'] = 894; + echo $b['l894']; + $b = $a; + $b['l895'] = 895; + echo $b['l895']; + $b = $a; + $b['l896'] = 896; + echo $b['l896']; + $b = $a; + $b['l897'] = 897; + echo $b['l897']; + $b = $a; + $b['l898'] = 898; + echo $b['l898']; + $b = $a; + $b['l899'] = 899; + echo $b['l899']; + $b = $a; + $b['l900'] = 900; + echo $b['l900']; + $b = $a; + $b['l901'] = 901; + echo $b['l901']; + $b = $a; + $b['l902'] = 902; + echo $b['l902']; + $b = $a; + $b['l903'] = 903; + echo $b['l903']; + $b = $a; + $b['l904'] = 904; + echo $b['l904']; + $b = $a; + $b['l905'] = 905; + echo $b['l905']; + $b = $a; + $b['l906'] = 906; + echo $b['l906']; + $b = $a; + $b['l907'] = 907; + echo $b['l907']; + $b = $a; + $b['l908'] = 908; + echo $b['l908']; + $b = $a; + $b['l909'] = 909; + echo $b['l909']; + $b = $a; + $b['l910'] = 910; + echo $b['l910']; + $b = $a; + $b['l911'] = 911; + echo $b['l911']; + $b = $a; + $b['l912'] = 912; + echo $b['l912']; + $b = $a; + $b['l913'] = 913; + echo $b['l913']; + $b = $a; + $b['l914'] = 914; + echo $b['l914']; + $b = $a; + $b['l915'] = 915; + echo $b['l915']; + $b = $a; + $b['l916'] = 916; + echo $b['l916']; + $b = $a; + $b['l917'] = 917; + echo $b['l917']; + $b = $a; + $b['l918'] = 918; + echo $b['l918']; + $b = $a; + $b['l919'] = 919; + echo $b['l919']; + $b = $a; + $b['l920'] = 920; + echo $b['l920']; + $b = $a; + $b['l921'] = 921; + echo $b['l921']; + $b = $a; + $b['l922'] = 922; + echo $b['l922']; + $b = $a; + $b['l923'] = 923; + echo $b['l923']; + $b = $a; + $b['l924'] = 924; + echo $b['l924']; + $b = $a; + $b['l925'] = 925; + echo $b['l925']; + $b = $a; + $b['l926'] = 926; + echo $b['l926']; + $b = $a; + $b['l927'] = 927; + echo $b['l927']; + $b = $a; + $b['l928'] = 928; + echo $b['l928']; + $b = $a; + $b['l929'] = 929; + echo $b['l929']; + $b = $a; + $b['l930'] = 930; + echo $b['l930']; + $b = $a; + $b['l931'] = 931; + echo $b['l931']; + $b = $a; + $b['l932'] = 932; + echo $b['l932']; + $b = $a; + $b['l933'] = 933; + echo $b['l933']; + $b = $a; + $b['l934'] = 934; + echo $b['l934']; + $b = $a; + $b['l935'] = 935; + echo $b['l935']; + $b = $a; + $b['l936'] = 936; + echo $b['l936']; + $b = $a; + $b['l937'] = 937; + echo $b['l937']; + $b = $a; + $b['l938'] = 938; + echo $b['l938']; + $b = $a; + $b['l939'] = 939; + echo $b['l939']; + $b = $a; + $b['l940'] = 940; + echo $b['l940']; + $b = $a; + $b['l941'] = 941; + echo $b['l941']; + $b = $a; + $b['l942'] = 942; + echo $b['l942']; + $b = $a; + $b['l943'] = 943; + echo $b['l943']; + $b = $a; + $b['l944'] = 944; + echo $b['l944']; + $b = $a; + $b['l945'] = 945; + echo $b['l945']; + $b = $a; + $b['l946'] = 946; + echo $b['l946']; + $b = $a; + $b['l947'] = 947; + echo $b['l947']; + $b = $a; + $b['l948'] = 948; + echo $b['l948']; + $b = $a; + $b['l949'] = 949; + echo $b['l949']; + $b = $a; + $b['l950'] = 950; + echo $b['l950']; + $b = $a; + $b['l951'] = 951; + echo $b['l951']; + $b = $a; + $b['l952'] = 952; + echo $b['l952']; + $b = $a; + $b['l953'] = 953; + echo $b['l953']; + $b = $a; + $b['l954'] = 954; + echo $b['l954']; + $b = $a; + $b['l955'] = 955; + echo $b['l955']; + $b = $a; + $b['l956'] = 956; + echo $b['l956']; + $b = $a; + $b['l957'] = 957; + echo $b['l957']; + $b = $a; + $b['l958'] = 958; + echo $b['l958']; + $b = $a; + $b['l959'] = 959; + echo $b['l959']; + $b = $a; + $b['l960'] = 960; + echo $b['l960']; + $b = $a; + $b['l961'] = 961; + echo $b['l961']; + $b = $a; + $b['l962'] = 962; + echo $b['l962']; + $b = $a; + $b['l963'] = 963; + echo $b['l963']; + $b = $a; + $b['l964'] = 964; + echo $b['l964']; + $b = $a; + $b['l965'] = 965; + echo $b['l965']; + $b = $a; + $b['l966'] = 966; + echo $b['l966']; + $b = $a; + $b['l967'] = 967; + echo $b['l967']; + $b = $a; + $b['l968'] = 968; + echo $b['l968']; + $b = $a; + $b['l969'] = 969; + echo $b['l969']; + $b = $a; + $b['l970'] = 970; + echo $b['l970']; + $b = $a; + $b['l971'] = 971; + echo $b['l971']; + $b = $a; + $b['l972'] = 972; + echo $b['l972']; + $b = $a; + $b['l973'] = 973; + echo $b['l973']; + $b = $a; + $b['l974'] = 974; + echo $b['l974']; + $b = $a; + $b['l975'] = 975; + echo $b['l975']; + $b = $a; + $b['l976'] = 976; + echo $b['l976']; + $b = $a; + $b['l977'] = 977; + echo $b['l977']; + $b = $a; + $b['l978'] = 978; + echo $b['l978']; + $b = $a; + $b['l979'] = 979; + echo $b['l979']; + $b = $a; + $b['l980'] = 980; + echo $b['l980']; + $b = $a; + $b['l981'] = 981; + echo $b['l981']; + $b = $a; + $b['l982'] = 982; + echo $b['l982']; + $b = $a; + $b['l983'] = 983; + echo $b['l983']; + $b = $a; + $b['l984'] = 984; + echo $b['l984']; + $b = $a; + $b['l985'] = 985; + echo $b['l985']; + $b = $a; + $b['l986'] = 986; + echo $b['l986']; + $b = $a; + $b['l987'] = 987; + echo $b['l987']; + $b = $a; + $b['l988'] = 988; + echo $b['l988']; + $b = $a; + $b['l989'] = 989; + echo $b['l989']; + $b = $a; + $b['l990'] = 990; + echo $b['l990']; + $b = $a; + $b['l991'] = 991; + echo $b['l991']; + $b = $a; + $b['l992'] = 992; + echo $b['l992']; + $b = $a; + $b['l993'] = 993; + echo $b['l993']; + $b = $a; + $b['l994'] = 994; + echo $b['l994']; + $b = $a; + $b['l995'] = 995; + echo $b['l995']; + $b = $a; + $b['l996'] = 996; + echo $b['l996']; + $b = $a; + $b['l997'] = 997; + echo $b['l997']; + $b = $a; + $b['l998'] = 998; + echo $b['l998']; + $b = $a; + $b['l999'] = 999; + echo $b['l999']; + $b = $a; + $b['l1000'] = 1000; + echo $b['l1000']; + $b = $a; + $b['l1001'] = 1001; + echo $b['l1001']; + $b = $a; + $b['l1002'] = 1002; + echo $b['l1002']; + $b = $a; + $b['l1003'] = 1003; + echo $b['l1003']; + $b = $a; + $b['l1004'] = 1004; + echo $b['l1004']; + $b = $a; + $b['l1005'] = 1005; + echo $b['l1005']; + $b = $a; + $b['l1006'] = 1006; + echo $b['l1006']; + $b = $a; + $b['l1007'] = 1007; + echo $b['l1007']; + $b = $a; + $b['l1008'] = 1008; + echo $b['l1008']; + $b = $a; + $b['l1009'] = 1009; + echo $b['l1009']; + $b = $a; + $b['l1010'] = 1010; + echo $b['l1010']; + $b = $a; + $b['l1011'] = 1011; + echo $b['l1011']; + $b = $a; + $b['l1012'] = 1012; + echo $b['l1012']; + $b = $a; + $b['l1013'] = 1013; + echo $b['l1013']; + $b = $a; + $b['l1014'] = 1014; + echo $b['l1014']; + $b = $a; + $b['l1015'] = 1015; + echo $b['l1015']; + $b = $a; + $b['l1016'] = 1016; + echo $b['l1016']; + $b = $a; + $b['l1017'] = 1017; + echo $b['l1017']; + $b = $a; + $b['l1018'] = 1018; + echo $b['l1018']; + $b = $a; + $b['l1019'] = 1019; + echo $b['l1019']; + $b = $a; + $b['l1020'] = 1020; + echo $b['l1020']; + $b = $a; + $b['l1021'] = 1021; + echo $b['l1021']; + $b = $a; + $b['l1022'] = 1022; + echo $b['l1022']; + $b = $a; + $b['l1023'] = 1023; + echo $b['l1023']; + $b = $a; + $b['l1024'] = 1024; + echo $b['l1024']; + $b = $a; + $b['l1025'] = 1025; + echo $b['l1025']; + $b = $a; + $b['l1026'] = 1026; + echo $b['l1026']; + $b = $a; + $b['l1027'] = 1027; + echo $b['l1027']; + $b = $a; + $b['l1028'] = 1028; + echo $b['l1028']; + $b = $a; + $b['l1029'] = 1029; + echo $b['l1029']; + $b = $a; + $b['l1030'] = 1030; + echo $b['l1030']; + $b = $a; + $b['l1031'] = 1031; + echo $b['l1031']; + $b = $a; + $b['l1032'] = 1032; + echo $b['l1032']; + $b = $a; + $b['l1033'] = 1033; + echo $b['l1033']; + $b = $a; + $b['l1034'] = 1034; + echo $b['l1034']; + $b = $a; + $b['l1035'] = 1035; + echo $b['l1035']; + $b = $a; + $b['l1036'] = 1036; + echo $b['l1036']; + $b = $a; + $b['l1037'] = 1037; + echo $b['l1037']; + $b = $a; + $b['l1038'] = 1038; + echo $b['l1038']; + $b = $a; + $b['l1039'] = 1039; + echo $b['l1039']; + $b = $a; + $b['l1040'] = 1040; + echo $b['l1040']; + $b = $a; + $b['l1041'] = 1041; + echo $b['l1041']; + $b = $a; + $b['l1042'] = 1042; + echo $b['l1042']; + $b = $a; + $b['l1043'] = 1043; + echo $b['l1043']; + $b = $a; + $b['l1044'] = 1044; + echo $b['l1044']; + $b = $a; + $b['l1045'] = 1045; + echo $b['l1045']; + $b = $a; + $b['l1046'] = 1046; + echo $b['l1046']; + $b = $a; + $b['l1047'] = 1047; + echo $b['l1047']; + $b = $a; + $b['l1048'] = 1048; + echo $b['l1048']; + $b = $a; + $b['l1049'] = 1049; + echo $b['l1049']; + $b = $a; + $b['l1050'] = 1050; + echo $b['l1050']; + $b = $a; + $b['l1051'] = 1051; + echo $b['l1051']; + $b = $a; + $b['l1052'] = 1052; + echo $b['l1052']; + $b = $a; + $b['l1053'] = 1053; + echo $b['l1053']; + $b = $a; + $b['l1054'] = 1054; + echo $b['l1054']; + $b = $a; + $b['l1055'] = 1055; + echo $b['l1055']; + $b = $a; + $b['l1056'] = 1056; + echo $b['l1056']; + $b = $a; + $b['l1057'] = 1057; + echo $b['l1057']; + $b = $a; + $b['l1058'] = 1058; + echo $b['l1058']; + $b = $a; + $b['l1059'] = 1059; + echo $b['l1059']; + $b = $a; + $b['l1060'] = 1060; + echo $b['l1060']; + $b = $a; + $b['l1061'] = 1061; + echo $b['l1061']; + $b = $a; + $b['l1062'] = 1062; + echo $b['l1062']; + $b = $a; + $b['l1063'] = 1063; + echo $b['l1063']; + $b = $a; + $b['l1064'] = 1064; + echo $b['l1064']; + $b = $a; + $b['l1065'] = 1065; + echo $b['l1065']; + $b = $a; + $b['l1066'] = 1066; + echo $b['l1066']; + $b = $a; + $b['l1067'] = 1067; + echo $b['l1067']; + $b = $a; + $b['l1068'] = 1068; + echo $b['l1068']; + $b = $a; + $b['l1069'] = 1069; + echo $b['l1069']; + $b = $a; + $b['l1070'] = 1070; + echo $b['l1070']; + $b = $a; + $b['l1071'] = 1071; + echo $b['l1071']; + $b = $a; + $b['l1072'] = 1072; + echo $b['l1072']; + $b = $a; + $b['l1073'] = 1073; + echo $b['l1073']; + $b = $a; + $b['l1074'] = 1074; + echo $b['l1074']; + $b = $a; + $b['l1075'] = 1075; + echo $b['l1075']; + $b = $a; + $b['l1076'] = 1076; + echo $b['l1076']; + $b = $a; + $b['l1077'] = 1077; + echo $b['l1077']; + $b = $a; + $b['l1078'] = 1078; + echo $b['l1078']; + $b = $a; + $b['l1079'] = 1079; + echo $b['l1079']; + $b = $a; + $b['l1080'] = 1080; + echo $b['l1080']; + $b = $a; + $b['l1081'] = 1081; + echo $b['l1081']; + $b = $a; + $b['l1082'] = 1082; + echo $b['l1082']; + $b = $a; + $b['l1083'] = 1083; + echo $b['l1083']; + $b = $a; + $b['l1084'] = 1084; + echo $b['l1084']; + $b = $a; + $b['l1085'] = 1085; + echo $b['l1085']; + $b = $a; + $b['l1086'] = 1086; + echo $b['l1086']; + $b = $a; + $b['l1087'] = 1087; + echo $b['l1087']; + $b = $a; + $b['l1088'] = 1088; + echo $b['l1088']; + $b = $a; + $b['l1089'] = 1089; + echo $b['l1089']; + $b = $a; + $b['l1090'] = 1090; + echo $b['l1090']; + $b = $a; + $b['l1091'] = 1091; + echo $b['l1091']; + $b = $a; + $b['l1092'] = 1092; + echo $b['l1092']; + $b = $a; + $b['l1093'] = 1093; + echo $b['l1093']; + $b = $a; + $b['l1094'] = 1094; + echo $b['l1094']; + $b = $a; + $b['l1095'] = 1095; + echo $b['l1095']; + $b = $a; + $b['l1096'] = 1096; + echo $b['l1096']; + $b = $a; + $b['l1097'] = 1097; + echo $b['l1097']; + $b = $a; + $b['l1098'] = 1098; + echo $b['l1098']; + $b = $a; + $b['l1099'] = 1099; + echo $b['l1099']; + $b = $a; + $b['l1100'] = 1100; + echo $b['l1100']; + $b = $a; + $b['l1101'] = 1101; + echo $b['l1101']; + $b = $a; + $b['l1102'] = 1102; + echo $b['l1102']; + $b = $a; + $b['l1103'] = 1103; + echo $b['l1103']; + $b = $a; + $b['l1104'] = 1104; + echo $b['l1104']; + $b = $a; + $b['l1105'] = 1105; + echo $b['l1105']; + $b = $a; + $b['l1106'] = 1106; + echo $b['l1106']; + $b = $a; + $b['l1107'] = 1107; + echo $b['l1107']; + $b = $a; + $b['l1108'] = 1108; + echo $b['l1108']; + $b = $a; + $b['l1109'] = 1109; + echo $b['l1109']; + $b = $a; + $b['l1110'] = 1110; + echo $b['l1110']; + $b = $a; + $b['l1111'] = 1111; + echo $b['l1111']; + $b = $a; + $b['l1112'] = 1112; + echo $b['l1112']; + $b = $a; + $b['l1113'] = 1113; + echo $b['l1113']; + $b = $a; + $b['l1114'] = 1114; + echo $b['l1114']; + $b = $a; + $b['l1115'] = 1115; + echo $b['l1115']; + $b = $a; + $b['l1116'] = 1116; + echo $b['l1116']; + $b = $a; + $b['l1117'] = 1117; + echo $b['l1117']; + $b = $a; + $b['l1118'] = 1118; + echo $b['l1118']; + $b = $a; + $b['l1119'] = 1119; + echo $b['l1119']; + $b = $a; + $b['l1120'] = 1120; + echo $b['l1120']; + $b = $a; + $b['l1121'] = 1121; + echo $b['l1121']; + $b = $a; + $b['l1122'] = 1122; + echo $b['l1122']; + $b = $a; + $b['l1123'] = 1123; + echo $b['l1123']; + $b = $a; + $b['l1124'] = 1124; + echo $b['l1124']; + $b = $a; + $b['l1125'] = 1125; + echo $b['l1125']; + $b = $a; + $b['l1126'] = 1126; + echo $b['l1126']; + $b = $a; + $b['l1127'] = 1127; + echo $b['l1127']; + $b = $a; + $b['l1128'] = 1128; + echo $b['l1128']; + $b = $a; + $b['l1129'] = 1129; + echo $b['l1129']; + $b = $a; + $b['l1130'] = 1130; + echo $b['l1130']; + $b = $a; + $b['l1131'] = 1131; + echo $b['l1131']; + $b = $a; + $b['l1132'] = 1132; + echo $b['l1132']; + $b = $a; + $b['l1133'] = 1133; + echo $b['l1133']; + $b = $a; + $b['l1134'] = 1134; + echo $b['l1134']; + $b = $a; + $b['l1135'] = 1135; + echo $b['l1135']; + $b = $a; + $b['l1136'] = 1136; + echo $b['l1136']; + $b = $a; + $b['l1137'] = 1137; + echo $b['l1137']; + $b = $a; + $b['l1138'] = 1138; + echo $b['l1138']; + $b = $a; + $b['l1139'] = 1139; + echo $b['l1139']; + $b = $a; + $b['l1140'] = 1140; + echo $b['l1140']; + $b = $a; + $b['l1141'] = 1141; + echo $b['l1141']; + $b = $a; + $b['l1142'] = 1142; + echo $b['l1142']; + $b = $a; + $b['l1143'] = 1143; + echo $b['l1143']; + $b = $a; + $b['l1144'] = 1144; + echo $b['l1144']; + $b = $a; + $b['l1145'] = 1145; + echo $b['l1145']; + $b = $a; + $b['l1146'] = 1146; + echo $b['l1146']; + $b = $a; + $b['l1147'] = 1147; + echo $b['l1147']; + $b = $a; + $b['l1148'] = 1148; + echo $b['l1148']; + $b = $a; + $b['l1149'] = 1149; + echo $b['l1149']; + $b = $a; + $b['l1150'] = 1150; + echo $b['l1150']; + $b = $a; + $b['l1151'] = 1151; + echo $b['l1151']; + $b = $a; + $b['l1152'] = 1152; + echo $b['l1152']; + $b = $a; + $b['l1153'] = 1153; + echo $b['l1153']; + $b = $a; + $b['l1154'] = 1154; + echo $b['l1154']; + $b = $a; + $b['l1155'] = 1155; + echo $b['l1155']; + $b = $a; + $b['l1156'] = 1156; + echo $b['l1156']; + $b = $a; + $b['l1157'] = 1157; + echo $b['l1157']; + $b = $a; + $b['l1158'] = 1158; + echo $b['l1158']; + $b = $a; + $b['l1159'] = 1159; + echo $b['l1159']; + $b = $a; + $b['l1160'] = 1160; + echo $b['l1160']; + $b = $a; + $b['l1161'] = 1161; + echo $b['l1161']; + $b = $a; + $b['l1162'] = 1162; + echo $b['l1162']; + $b = $a; + $b['l1163'] = 1163; + echo $b['l1163']; + $b = $a; + $b['l1164'] = 1164; + echo $b['l1164']; + $b = $a; + $b['l1165'] = 1165; + echo $b['l1165']; + $b = $a; + $b['l1166'] = 1166; + echo $b['l1166']; + $b = $a; + $b['l1167'] = 1167; + echo $b['l1167']; + $b = $a; + $b['l1168'] = 1168; + echo $b['l1168']; + $b = $a; + $b['l1169'] = 1169; + echo $b['l1169']; + $b = $a; + $b['l1170'] = 1170; + echo $b['l1170']; + $b = $a; + $b['l1171'] = 1171; + echo $b['l1171']; + $b = $a; + $b['l1172'] = 1172; + echo $b['l1172']; + $b = $a; + $b['l1173'] = 1173; + echo $b['l1173']; + $b = $a; + $b['l1174'] = 1174; + echo $b['l1174']; + $b = $a; + $b['l1175'] = 1175; + echo $b['l1175']; + $b = $a; + $b['l1176'] = 1176; + echo $b['l1176']; + $b = $a; + $b['l1177'] = 1177; + echo $b['l1177']; + $b = $a; + $b['l1178'] = 1178; + echo $b['l1178']; + $b = $a; + $b['l1179'] = 1179; + echo $b['l1179']; + $b = $a; + $b['l1180'] = 1180; + echo $b['l1180']; + $b = $a; + $b['l1181'] = 1181; + echo $b['l1181']; + $b = $a; + $b['l1182'] = 1182; + echo $b['l1182']; + $b = $a; + $b['l1183'] = 1183; + echo $b['l1183']; + $b = $a; + $b['l1184'] = 1184; + echo $b['l1184']; + $b = $a; + $b['l1185'] = 1185; + echo $b['l1185']; + $b = $a; + $b['l1186'] = 1186; + echo $b['l1186']; + $b = $a; + $b['l1187'] = 1187; + echo $b['l1187']; + $b = $a; + $b['l1188'] = 1188; + echo $b['l1188']; + $b = $a; + $b['l1189'] = 1189; + echo $b['l1189']; + $b = $a; + $b['l1190'] = 1190; + echo $b['l1190']; + $b = $a; + $b['l1191'] = 1191; + echo $b['l1191']; + $b = $a; + $b['l1192'] = 1192; + echo $b['l1192']; + $b = $a; + $b['l1193'] = 1193; + echo $b['l1193']; + $b = $a; + $b['l1194'] = 1194; + echo $b['l1194']; + $b = $a; + $b['l1195'] = 1195; + echo $b['l1195']; + $b = $a; + $b['l1196'] = 1196; + echo $b['l1196']; + $b = $a; + $b['l1197'] = 1197; + echo $b['l1197']; + $b = $a; + $b['l1198'] = 1198; + echo $b['l1198']; + $b = $a; + $b['l1199'] = 1199; + echo $b['l1199']; + $b = $a; + $b['l1200'] = 1200; + echo $b['l1200']; + $b = $a; + $b['l1201'] = 1201; + echo $b['l1201']; + $b = $a; + $b['l1202'] = 1202; + echo $b['l1202']; + $b = $a; + $b['l1203'] = 1203; + echo $b['l1203']; + $b = $a; + $b['l1204'] = 1204; + echo $b['l1204']; + $b = $a; + $b['l1205'] = 1205; + echo $b['l1205']; + $b = $a; + $b['l1206'] = 1206; + echo $b['l1206']; + $b = $a; + $b['l1207'] = 1207; + echo $b['l1207']; + $b = $a; + $b['l1208'] = 1208; + echo $b['l1208']; + $b = $a; + $b['l1209'] = 1209; + echo $b['l1209']; + $b = $a; + $b['l1210'] = 1210; + echo $b['l1210']; + $b = $a; + $b['l1211'] = 1211; + echo $b['l1211']; + $b = $a; + $b['l1212'] = 1212; + echo $b['l1212']; + $b = $a; + $b['l1213'] = 1213; + echo $b['l1213']; + $b = $a; + $b['l1214'] = 1214; + echo $b['l1214']; + $b = $a; + $b['l1215'] = 1215; + echo $b['l1215']; + $b = $a; + $b['l1216'] = 1216; + echo $b['l1216']; + $b = $a; + $b['l1217'] = 1217; + echo $b['l1217']; + $b = $a; + $b['l1218'] = 1218; + echo $b['l1218']; + $b = $a; + $b['l1219'] = 1219; + echo $b['l1219']; + $b = $a; + $b['l1220'] = 1220; + echo $b['l1220']; + $b = $a; + $b['l1221'] = 1221; + echo $b['l1221']; + $b = $a; + $b['l1222'] = 1222; + echo $b['l1222']; + $b = $a; + $b['l1223'] = 1223; + echo $b['l1223']; + $b = $a; + $b['l1224'] = 1224; + echo $b['l1224']; + $b = $a; + $b['l1225'] = 1225; + echo $b['l1225']; + $b = $a; + $b['l1226'] = 1226; + echo $b['l1226']; + $b = $a; + $b['l1227'] = 1227; + echo $b['l1227']; + $b = $a; + $b['l1228'] = 1228; + echo $b['l1228']; + $b = $a; + $b['l1229'] = 1229; + echo $b['l1229']; + $b = $a; + $b['l1230'] = 1230; + echo $b['l1230']; + $b = $a; + $b['l1231'] = 1231; + echo $b['l1231']; + $b = $a; + $b['l1232'] = 1232; + echo $b['l1232']; + $b = $a; + $b['l1233'] = 1233; + echo $b['l1233']; + $b = $a; + $b['l1234'] = 1234; + echo $b['l1234']; + $b = $a; + $b['l1235'] = 1235; + echo $b['l1235']; + $b = $a; + $b['l1236'] = 1236; + echo $b['l1236']; + $b = $a; + $b['l1237'] = 1237; + echo $b['l1237']; + $b = $a; + $b['l1238'] = 1238; + echo $b['l1238']; + $b = $a; + $b['l1239'] = 1239; + echo $b['l1239']; + $b = $a; + $b['l1240'] = 1240; + echo $b['l1240']; + $b = $a; + $b['l1241'] = 1241; + echo $b['l1241']; + $b = $a; + $b['l1242'] = 1242; + echo $b['l1242']; + $b = $a; + $b['l1243'] = 1243; + echo $b['l1243']; + $b = $a; + $b['l1244'] = 1244; + echo $b['l1244']; + $b = $a; + $b['l1245'] = 1245; + echo $b['l1245']; + $b = $a; + $b['l1246'] = 1246; + echo $b['l1246']; + $b = $a; + $b['l1247'] = 1247; + echo $b['l1247']; + $b = $a; + $b['l1248'] = 1248; + echo $b['l1248']; + $b = $a; + $b['l1249'] = 1249; + echo $b['l1249']; + $b = $a; + $b['l1250'] = 1250; + echo $b['l1250']; + $b = $a; + $b['l1251'] = 1251; + echo $b['l1251']; + $b = $a; + $b['l1252'] = 1252; + echo $b['l1252']; + $b = $a; + $b['l1253'] = 1253; + echo $b['l1253']; + $b = $a; + $b['l1254'] = 1254; + echo $b['l1254']; + $b = $a; + $b['l1255'] = 1255; + echo $b['l1255']; + $b = $a; + $b['l1256'] = 1256; + echo $b['l1256']; + $b = $a; + $b['l1257'] = 1257; + echo $b['l1257']; + $b = $a; + $b['l1258'] = 1258; + echo $b['l1258']; + $b = $a; + $b['l1259'] = 1259; + echo $b['l1259']; + $b = $a; + $b['l1260'] = 1260; + echo $b['l1260']; + $b = $a; + $b['l1261'] = 1261; + echo $b['l1261']; + $b = $a; + $b['l1262'] = 1262; + echo $b['l1262']; + $b = $a; + $b['l1263'] = 1263; + echo $b['l1263']; + $b = $a; + $b['l1264'] = 1264; + echo $b['l1264']; + $b = $a; + $b['l1265'] = 1265; + echo $b['l1265']; + $b = $a; + $b['l1266'] = 1266; + echo $b['l1266']; + $b = $a; + $b['l1267'] = 1267; + echo $b['l1267']; + $b = $a; + $b['l1268'] = 1268; + echo $b['l1268']; + $b = $a; + $b['l1269'] = 1269; + echo $b['l1269']; + $b = $a; + $b['l1270'] = 1270; + echo $b['l1270']; + $b = $a; + $b['l1271'] = 1271; + echo $b['l1271']; + $b = $a; + $b['l1272'] = 1272; + echo $b['l1272']; + $b = $a; + $b['l1273'] = 1273; + echo $b['l1273']; + $b = $a; + $b['l1274'] = 1274; + echo $b['l1274']; + $b = $a; + $b['l1275'] = 1275; + echo $b['l1275']; + $b = $a; + $b['l1276'] = 1276; + echo $b['l1276']; + $b = $a; + $b['l1277'] = 1277; + echo $b['l1277']; + $b = $a; + $b['l1278'] = 1278; + echo $b['l1278']; + $b = $a; + $b['l1279'] = 1279; + echo $b['l1279']; + $b = $a; + $b['l1280'] = 1280; + echo $b['l1280']; + $b = $a; + $b['l1281'] = 1281; + echo $b['l1281']; + $b = $a; + $b['l1282'] = 1282; + echo $b['l1282']; + $b = $a; + $b['l1283'] = 1283; + echo $b['l1283']; + $b = $a; + $b['l1284'] = 1284; + echo $b['l1284']; + $b = $a; + $b['l1285'] = 1285; + echo $b['l1285']; + $b = $a; + $b['l1286'] = 1286; + echo $b['l1286']; + $b = $a; + $b['l1287'] = 1287; + echo $b['l1287']; + $b = $a; + $b['l1288'] = 1288; + echo $b['l1288']; + $b = $a; + $b['l1289'] = 1289; + echo $b['l1289']; + $b = $a; + $b['l1290'] = 1290; + echo $b['l1290']; + $b = $a; + $b['l1291'] = 1291; + echo $b['l1291']; + $b = $a; + $b['l1292'] = 1292; + echo $b['l1292']; + $b = $a; + $b['l1293'] = 1293; + echo $b['l1293']; + $b = $a; + $b['l1294'] = 1294; + echo $b['l1294']; + $b = $a; + $b['l1295'] = 1295; + echo $b['l1295']; + $b = $a; + $b['l1296'] = 1296; + echo $b['l1296']; + $b = $a; + $b['l1297'] = 1297; + echo $b['l1297']; + $b = $a; + $b['l1298'] = 1298; + echo $b['l1298']; + $b = $a; + $b['l1299'] = 1299; + echo $b['l1299']; + $b = $a; + $b['l1300'] = 1300; + echo $b['l1300']; + $b = $a; + $b['l1301'] = 1301; + echo $b['l1301']; + $b = $a; + $b['l1302'] = 1302; + echo $b['l1302']; + $b = $a; + $b['l1303'] = 1303; + echo $b['l1303']; + $b = $a; + $b['l1304'] = 1304; + echo $b['l1304']; + $b = $a; + $b['l1305'] = 1305; + echo $b['l1305']; + $b = $a; + $b['l1306'] = 1306; + echo $b['l1306']; + $b = $a; + $b['l1307'] = 1307; + echo $b['l1307']; + $b = $a; + $b['l1308'] = 1308; + echo $b['l1308']; + $b = $a; + $b['l1309'] = 1309; + echo $b['l1309']; + $b = $a; + $b['l1310'] = 1310; + echo $b['l1310']; + $b = $a; + $b['l1311'] = 1311; + echo $b['l1311']; + $b = $a; + $b['l1312'] = 1312; + echo $b['l1312']; + $b = $a; + $b['l1313'] = 1313; + echo $b['l1313']; + $b = $a; + $b['l1314'] = 1314; + echo $b['l1314']; + $b = $a; + $b['l1315'] = 1315; + echo $b['l1315']; + $b = $a; + $b['l1316'] = 1316; + echo $b['l1316']; + $b = $a; + $b['l1317'] = 1317; + echo $b['l1317']; + $b = $a; + $b['l1318'] = 1318; + echo $b['l1318']; + $b = $a; + $b['l1319'] = 1319; + echo $b['l1319']; + $b = $a; + $b['l1320'] = 1320; + echo $b['l1320']; + $b = $a; + $b['l1321'] = 1321; + echo $b['l1321']; + $b = $a; + $b['l1322'] = 1322; + echo $b['l1322']; + $b = $a; + $b['l1323'] = 1323; + echo $b['l1323']; + $b = $a; + $b['l1324'] = 1324; + echo $b['l1324']; + $b = $a; + $b['l1325'] = 1325; + echo $b['l1325']; + $b = $a; + $b['l1326'] = 1326; + echo $b['l1326']; + $b = $a; + $b['l1327'] = 1327; + echo $b['l1327']; + $b = $a; + $b['l1328'] = 1328; + echo $b['l1328']; + $b = $a; + $b['l1329'] = 1329; + echo $b['l1329']; + $b = $a; + $b['l1330'] = 1330; + echo $b['l1330']; + $b = $a; + $b['l1331'] = 1331; + echo $b['l1331']; + $b = $a; + $b['l1332'] = 1332; + echo $b['l1332']; + $b = $a; + $b['l1333'] = 1333; + echo $b['l1333']; + $b = $a; + $b['l1334'] = 1334; + echo $b['l1334']; + $b = $a; + $b['l1335'] = 1335; + echo $b['l1335']; + $b = $a; + $b['l1336'] = 1336; + echo $b['l1336']; + $b = $a; + $b['l1337'] = 1337; + echo $b['l1337']; + $b = $a; + $b['l1338'] = 1338; + echo $b['l1338']; + $b = $a; + $b['l1339'] = 1339; + echo $b['l1339']; + $b = $a; + $b['l1340'] = 1340; + echo $b['l1340']; + $b = $a; + $b['l1341'] = 1341; + echo $b['l1341']; + $b = $a; + $b['l1342'] = 1342; + echo $b['l1342']; + $b = $a; + $b['l1343'] = 1343; + echo $b['l1343']; + $b = $a; + $b['l1344'] = 1344; + echo $b['l1344']; + $b = $a; + $b['l1345'] = 1345; + echo $b['l1345']; + $b = $a; + $b['l1346'] = 1346; + echo $b['l1346']; + $b = $a; + $b['l1347'] = 1347; + echo $b['l1347']; + $b = $a; + $b['l1348'] = 1348; + echo $b['l1348']; + $b = $a; + $b['l1349'] = 1349; + echo $b['l1349']; + $b = $a; + $b['l1350'] = 1350; + echo $b['l1350']; + $b = $a; + $b['l1351'] = 1351; + echo $b['l1351']; + $b = $a; + $b['l1352'] = 1352; + echo $b['l1352']; + $b = $a; + $b['l1353'] = 1353; + echo $b['l1353']; + $b = $a; + $b['l1354'] = 1354; + echo $b['l1354']; + $b = $a; + $b['l1355'] = 1355; + echo $b['l1355']; + $b = $a; + $b['l1356'] = 1356; + echo $b['l1356']; + $b = $a; + $b['l1357'] = 1357; + echo $b['l1357']; + $b = $a; + $b['l1358'] = 1358; + echo $b['l1358']; + $b = $a; + $b['l1359'] = 1359; + echo $b['l1359']; + $b = $a; + $b['l1360'] = 1360; + echo $b['l1360']; + $b = $a; + $b['l1361'] = 1361; + echo $b['l1361']; + $b = $a; + $b['l1362'] = 1362; + echo $b['l1362']; + $b = $a; + $b['l1363'] = 1363; + echo $b['l1363']; + $b = $a; + $b['l1364'] = 1364; + echo $b['l1364']; + $b = $a; + $b['l1365'] = 1365; + echo $b['l1365']; + $b = $a; + $b['l1366'] = 1366; + echo $b['l1366']; + $b = $a; + $b['l1367'] = 1367; + echo $b['l1367']; + $b = $a; + $b['l1368'] = 1368; + echo $b['l1368']; + $b = $a; + $b['l1369'] = 1369; + echo $b['l1369']; + $b = $a; + $b['l1370'] = 1370; + echo $b['l1370']; + $b = $a; + $b['l1371'] = 1371; + echo $b['l1371']; + $b = $a; + $b['l1372'] = 1372; + echo $b['l1372']; + $b = $a; + $b['l1373'] = 1373; + echo $b['l1373']; + $b = $a; + $b['l1374'] = 1374; + echo $b['l1374']; + $b = $a; + $b['l1375'] = 1375; + echo $b['l1375']; + $b = $a; + $b['l1376'] = 1376; + echo $b['l1376']; + $b = $a; + $b['l1377'] = 1377; + echo $b['l1377']; + $b = $a; + $b['l1378'] = 1378; + echo $b['l1378']; + $b = $a; + $b['l1379'] = 1379; + echo $b['l1379']; + $b = $a; + $b['l1380'] = 1380; + echo $b['l1380']; + $b = $a; + $b['l1381'] = 1381; + echo $b['l1381']; + $b = $a; + $b['l1382'] = 1382; + echo $b['l1382']; + $b = $a; + $b['l1383'] = 1383; + echo $b['l1383']; + $b = $a; + $b['l1384'] = 1384; + echo $b['l1384']; + $b = $a; + $b['l1385'] = 1385; + echo $b['l1385']; + $b = $a; + $b['l1386'] = 1386; + echo $b['l1386']; + $b = $a; + $b['l1387'] = 1387; + echo $b['l1387']; + $b = $a; + $b['l1388'] = 1388; + echo $b['l1388']; + $b = $a; + $b['l1389'] = 1389; + echo $b['l1389']; + $b = $a; + $b['l1390'] = 1390; + echo $b['l1390']; + $b = $a; + $b['l1391'] = 1391; + echo $b['l1391']; + $b = $a; + $b['l1392'] = 1392; + echo $b['l1392']; + $b = $a; + $b['l1393'] = 1393; + echo $b['l1393']; + $b = $a; + $b['l1394'] = 1394; + echo $b['l1394']; + $b = $a; + $b['l1395'] = 1395; + echo $b['l1395']; + $b = $a; + $b['l1396'] = 1396; + echo $b['l1396']; + $b = $a; + $b['l1397'] = 1397; + echo $b['l1397']; + $b = $a; + $b['l1398'] = 1398; + echo $b['l1398']; + $b = $a; + $b['l1399'] = 1399; + echo $b['l1399']; + $b = $a; + $b['l1400'] = 1400; + echo $b['l1400']; + $b = $a; + $b['l1401'] = 1401; + echo $b['l1401']; + $b = $a; + $b['l1402'] = 1402; + echo $b['l1402']; + $b = $a; + $b['l1403'] = 1403; + echo $b['l1403']; + $b = $a; + $b['l1404'] = 1404; + echo $b['l1404']; + $b = $a; + $b['l1405'] = 1405; + echo $b['l1405']; + $b = $a; + $b['l1406'] = 1406; + echo $b['l1406']; + $b = $a; + $b['l1407'] = 1407; + echo $b['l1407']; + $b = $a; + $b['l1408'] = 1408; + echo $b['l1408']; + $b = $a; + $b['l1409'] = 1409; + echo $b['l1409']; + $b = $a; + $b['l1410'] = 1410; + echo $b['l1410']; + $b = $a; + $b['l1411'] = 1411; + echo $b['l1411']; + $b = $a; + $b['l1412'] = 1412; + echo $b['l1412']; + $b = $a; + $b['l1413'] = 1413; + echo $b['l1413']; + $b = $a; + $b['l1414'] = 1414; + echo $b['l1414']; + $b = $a; + $b['l1415'] = 1415; + echo $b['l1415']; + $b = $a; + $b['l1416'] = 1416; + echo $b['l1416']; + $b = $a; + $b['l1417'] = 1417; + echo $b['l1417']; + $b = $a; + $b['l1418'] = 1418; + echo $b['l1418']; + $b = $a; + $b['l1419'] = 1419; + echo $b['l1419']; + $b = $a; + $b['l1420'] = 1420; + echo $b['l1420']; + $b = $a; + $b['l1421'] = 1421; + echo $b['l1421']; + $b = $a; + $b['l1422'] = 1422; + echo $b['l1422']; + $b = $a; + $b['l1423'] = 1423; + echo $b['l1423']; + $b = $a; + $b['l1424'] = 1424; + echo $b['l1424']; + $b = $a; + $b['l1425'] = 1425; + echo $b['l1425']; + $b = $a; + $b['l1426'] = 1426; + echo $b['l1426']; + $b = $a; + $b['l1427'] = 1427; + echo $b['l1427']; + $b = $a; + $b['l1428'] = 1428; + echo $b['l1428']; + $b = $a; + $b['l1429'] = 1429; + echo $b['l1429']; + $b = $a; + $b['l1430'] = 1430; + echo $b['l1430']; + $b = $a; + $b['l1431'] = 1431; + echo $b['l1431']; + $b = $a; + $b['l1432'] = 1432; + echo $b['l1432']; + $b = $a; + $b['l1433'] = 1433; + echo $b['l1433']; + $b = $a; + $b['l1434'] = 1434; + echo $b['l1434']; + $b = $a; + $b['l1435'] = 1435; + echo $b['l1435']; + $b = $a; + $b['l1436'] = 1436; + echo $b['l1436']; + $b = $a; + $b['l1437'] = 1437; + echo $b['l1437']; + $b = $a; + $b['l1438'] = 1438; + echo $b['l1438']; + $b = $a; + $b['l1439'] = 1439; + echo $b['l1439']; + $b = $a; + $b['l1440'] = 1440; + echo $b['l1440']; + $b = $a; + $b['l1441'] = 1441; + echo $b['l1441']; + $b = $a; + $b['l1442'] = 1442; + echo $b['l1442']; + $b = $a; + $b['l1443'] = 1443; + echo $b['l1443']; + $b = $a; + $b['l1444'] = 1444; + echo $b['l1444']; + $b = $a; + $b['l1445'] = 1445; + echo $b['l1445']; + $b = $a; + $b['l1446'] = 1446; + echo $b['l1446']; + $b = $a; + $b['l1447'] = 1447; + echo $b['l1447']; + $b = $a; + $b['l1448'] = 1448; + echo $b['l1448']; + $b = $a; + $b['l1449'] = 1449; + echo $b['l1449']; + $b = $a; + $b['l1450'] = 1450; + echo $b['l1450']; + $b = $a; + $b['l1451'] = 1451; + echo $b['l1451']; + $b = $a; + $b['l1452'] = 1452; + echo $b['l1452']; + $b = $a; + $b['l1453'] = 1453; + echo $b['l1453']; + $b = $a; + $b['l1454'] = 1454; + echo $b['l1454']; + $b = $a; + $b['l1455'] = 1455; + echo $b['l1455']; + $b = $a; + $b['l1456'] = 1456; + echo $b['l1456']; + $b = $a; + $b['l1457'] = 1457; + echo $b['l1457']; + $b = $a; + $b['l1458'] = 1458; + echo $b['l1458']; + $b = $a; + $b['l1459'] = 1459; + echo $b['l1459']; + $b = $a; + $b['l1460'] = 1460; + echo $b['l1460']; + $b = $a; + $b['l1461'] = 1461; + echo $b['l1461']; + $b = $a; + $b['l1462'] = 1462; + echo $b['l1462']; + $b = $a; + $b['l1463'] = 1463; + echo $b['l1463']; + $b = $a; + $b['l1464'] = 1464; + echo $b['l1464']; + $b = $a; + $b['l1465'] = 1465; + echo $b['l1465']; + $b = $a; + $b['l1466'] = 1466; + echo $b['l1466']; + $b = $a; + $b['l1467'] = 1467; + echo $b['l1467']; + $b = $a; + $b['l1468'] = 1468; + echo $b['l1468']; + $b = $a; + $b['l1469'] = 1469; + echo $b['l1469']; + $b = $a; + $b['l1470'] = 1470; + echo $b['l1470']; + $b = $a; + $b['l1471'] = 1471; + echo $b['l1471']; + $b = $a; + $b['l1472'] = 1472; + echo $b['l1472']; + $b = $a; + $b['l1473'] = 1473; + echo $b['l1473']; + $b = $a; + $b['l1474'] = 1474; + echo $b['l1474']; + $b = $a; + $b['l1475'] = 1475; + echo $b['l1475']; + $b = $a; + $b['l1476'] = 1476; + echo $b['l1476']; + $b = $a; + $b['l1477'] = 1477; + echo $b['l1477']; + $b = $a; + $b['l1478'] = 1478; + echo $b['l1478']; + $b = $a; + $b['l1479'] = 1479; + echo $b['l1479']; + $b = $a; + $b['l1480'] = 1480; + echo $b['l1480']; + $b = $a; + $b['l1481'] = 1481; + echo $b['l1481']; + $b = $a; + $b['l1482'] = 1482; + echo $b['l1482']; + $b = $a; + $b['l1483'] = 1483; + echo $b['l1483']; + $b = $a; + $b['l1484'] = 1484; + echo $b['l1484']; + $b = $a; + $b['l1485'] = 1485; + echo $b['l1485']; + $b = $a; + $b['l1486'] = 1486; + echo $b['l1486']; + $b = $a; + $b['l1487'] = 1487; + echo $b['l1487']; + $b = $a; + $b['l1488'] = 1488; + echo $b['l1488']; + $b = $a; + $b['l1489'] = 1489; + echo $b['l1489']; + $b = $a; + $b['l1490'] = 1490; + echo $b['l1490']; + $b = $a; + $b['l1491'] = 1491; + echo $b['l1491']; + $b = $a; + $b['l1492'] = 1492; + echo $b['l1492']; + $b = $a; + $b['l1493'] = 1493; + echo $b['l1493']; + $b = $a; + $b['l1494'] = 1494; + echo $b['l1494']; + $b = $a; + $b['l1495'] = 1495; + echo $b['l1495']; + $b = $a; + $b['l1496'] = 1496; + echo $b['l1496']; + $b = $a; + $b['l1497'] = 1497; + echo $b['l1497']; + $b = $a; + $b['l1498'] = 1498; + echo $b['l1498']; + $b = $a; + $b['l1499'] = 1499; + echo $b['l1499']; + $b = $a; + $b['l1500'] = 1500; + echo $b['l1500']; +} From a9c0185ef31cf45271ad87acd0e5abcccea07ebd Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Mon, 14 Sep 2026 17:39:30 +0200 Subject: [PATCH 5/7] Write a shape's optional keys as optional into a general array's item shape ArrayType::setExistingOffsetValueType() merged a written constant array into the item shape all-or-nothing: once with every key required and once with every optional key unset. A written shape whose optional keys can be present independently (a nested `$a[$i][$j][$k]['x'] = ...` write in a loop) then came out as `array{}|array{k1: T, ..., kN: T}`, which is unsound for a value holding only some of the keys. Optional keys are now written as optional: an existing key keeps its certainty and unions the value, a missing one is added as optional. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01DfQHLTyyoMfjfa4sXJCGa5 --- src/Type/ArrayType.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Type/ArrayType.php b/src/Type/ArrayType.php index 66810275050..66ea8ae7b0b 100644 --- a/src/Type/ArrayType.php +++ b/src/Type/ArrayType.php @@ -453,7 +453,22 @@ public function setExistingOffsetValueType(Type $offsetType, Type $valueType): T if ($this->itemType->isConstantArray()->yes() && $valueType->isConstantArray()->yes()) { $newItemTypes = []; + $itemConstantArrays = $this->itemType->getConstantArrays(); foreach ($valueType->getConstantArrays() as $constArray) { + if ($constArray->getOptionalKeys() !== [] && count($itemConstantArrays) === 1) { + // A written shape with optional keys is not all-or-nothing: each + // optional key may or may not be present on its own, so it is + // written as optional (present keys keep their certainty, the + // value unions with what the key held) instead of once with every + // key required and once with every optional key unset. + $builder = ConstantArrayTypeBuilder::createFromConstantArray($itemConstantArrays[0]); + foreach ($constArray->getKeyTypes() as $i => $keyType) { + $builder->setOffsetValueType($keyType, $constArray->getOffsetValueType($keyType), $constArray->isOptionalKey($i)); + } + $newItemTypes[] = TypeCombinator::intersect($builder->getArray(), ...TypeUtils::getAccessoryTypes($this->itemType)); + continue; + } + $newItemType = $this->itemType; $optionalKeyTypes = []; foreach ($constArray->getKeyTypes() as $i => $keyType) { From 9bfe5ccc9b1f3692220881539f599f7bf598197b Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Mon, 14 Sep 2026 17:39:30 +0200 Subject: [PATCH 6/7] Do not expand optional-key shapes into every variant before loop widening MutatingScope::generalizeType() flattened both sides with TypeUtils::flattenTypes(), which turns a constant array with N optional keys into its 2^N concrete variants (four lossy representatives above ten) - only for the union right after to merge them back into the same shape, paying the pairwise reduceArrays() pass for hundreds of variants on every loop iteration. A method building a shape from a dozen conditional writes spent 1.8 s there. The per-key widening reads keys, values and optionality straight from the shape, so only unions are split now. The bug-13637 fixture keeps the loop's int<0, 8> bound on the middle key (the comment had called the previous `int` a residual) and describes the innermost level as the optional-key shape it is. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01DfQHLTyyoMfjfa4sXJCGa5 --- src/Analyser/MutatingScope.php | 29 +- tests/PHPStan/Analyser/ScopeTest.php | 9 +- tests/PHPStan/Analyser/nsrt/bug-13637.php | 8 +- .../data/loop-widening-optional-keys.php | 272 ++++++++++++++++++ 4 files changed, 310 insertions(+), 8 deletions(-) create mode 100644 tests/bench/data/loop-widening-optional-keys.php diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index d0eb57ef6aa..f8e4744d7f1 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -5006,6 +5006,31 @@ private function generalizeVariableTypeHolders( return $newVariableTypeHolders; } + /** + * TypeUtils::flattenTypes() expands a shape with optional keys into every + * concrete variant (2^N of them, four lossy representatives above ten), + * only for the union below to merge them back into the very same shape - + * quadratic in the number of variants. The per-key widening reads the + * shape's keys, values and optionality directly, so only unions are split. + * + * @return list + */ + private function flattenUnionForGeneralization(Type $type): array + { + if (!$type instanceof UnionType) { + return [$type]; + } + + $types = []; + foreach ($type->getTypes() as $innerType) { + foreach ($this->flattenUnionForGeneralization($innerType) as $flattenedType) { + $types[] = $flattenedType; + } + } + + return $types; + } + private function generalizeType(Type $a, Type $b, int $depth): Type { if ($a->equals($b)) { @@ -5033,8 +5058,8 @@ private function generalizeType(Type $a, Type $b, int $depth): Type $otherTypes = []; foreach ([ - 'a' => TypeUtils::flattenTypes($a), - 'b' => TypeUtils::flattenTypes($b), + 'a' => $this->flattenUnionForGeneralization($a), + 'b' => $this->flattenUnionForGeneralization($b), ] as $key => $types) { foreach ($types as $type) { if ($type instanceof ConstantIntegerType) { diff --git a/tests/PHPStan/Analyser/ScopeTest.php b/tests/PHPStan/Analyser/ScopeTest.php index 88d9753efc1..78d88cf8d1d 100644 --- a/tests/PHPStan/Analyser/ScopeTest.php +++ b/tests/PHPStan/Analyser/ScopeTest.php @@ -6,6 +6,7 @@ use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Name\FullyQualified; +use PHPStan\DependencyInjection\BleedingEdgeToggle; use PHPStan\Node\Expr\PossiblyImpureCallExpr; use PHPStan\Testing\PHPStanTestCase; use PHPStan\TrinaryLogic; @@ -27,7 +28,11 @@ class ScopeTest extends PHPStanTestCase public static function dataGeneralize(): array { - return [ + // A directly constructed shape is a legacy (unsealed) one only while bleeding + // edge is off - the toggle is process-global, and PHPUnit 9 evaluates the + // provider after earlier test classes may have left it on. The widening + // contract below is the legacy one, so the inputs are pinned to it. + return BleedingEdgeToggle::withBleedingEdge(false, static fn (): array => [ [ new ConstantStringType('a'), new ConstantStringType('a'), @@ -229,7 +234,7 @@ public static function dataGeneralize(): array IntegerRangeType::fromInterval(null, 16), 'int', ], - ]; + ]); } #[DataProvider('dataGeneralize')] diff --git a/tests/PHPStan/Analyser/nsrt/bug-13637.php b/tests/PHPStan/Analyser/nsrt/bug-13637.php index 0176f95a081..ca5fe8b73f6 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-13637.php +++ b/tests/PHPStan/Analyser/nsrt/bug-13637.php @@ -17,10 +17,10 @@ function doesNotWork(): void } // The reported regression (innermost values widening to `int<0, max>`) is - // fixed: they stay `int<0, 4>`. The middle key degenerates to `int` rather - // than the ideal `int<0, 8>` — a minor key-precision residual in 3-level - // nesting, not the value-widening bug from the issue. - assertType('non-empty-array, non-empty-array, array{abc: int<0, 4>, def?: int<0, 4>, ghi?: int<0, 4>}>>>', $final); + // fixed: they stay `int<0, 4>`, and the middle key keeps the loop's + // `int<0, 8>` bound now that widening no longer expands optional-key + // shapes into every variant before merging them back. + assertType('non-empty-array, non-empty-array, non-empty-array{3?: array{abc: int<0, 4>, def?: int<0, 4>, ghi?: int<0, 4>}, 1?: array{abc: int<0, 4>, def?: int<0, 4>, ghi?: int<0, 4>}, 2?: array{abc: int<0, 4>, def?: int<0, 4>, ghi?: int<0, 4>}, 4?: array{abc: int<0, 4>, def?: int<0, 4>, ghi?: int<0, 4>}, 5?: array{abc: int<0, 4>, def?: int<0, 4>, ghi?: int<0, 4>}, 6?: array{abc: int<0, 4>, def?: int<0, 4>, ghi?: int<0, 4>}, 7?: array{abc: int<0, 4>, def?: int<0, 4>, ghi?: int<0, 4>}, 8?: array{abc: int<0, 4>, def?: int<0, 4>, ghi?: int<0, 4>}, 9?: array{abc: int<0, 4>, def?: int<0, 4>, ghi?: int<0, 4>}}>>', $final); } function thisWorks(): void diff --git a/tests/bench/data/loop-widening-optional-keys.php b/tests/bench/data/loop-widening-optional-keys.php new file mode 100644 index 00000000000..fd568da8a82 --- /dev/null +++ b/tests/bench/data/loop-widening-optional-keys.php @@ -0,0 +1,272 @@ + */ + public array $list1 = []; + + /** @var list */ + public array $list2 = []; + + /** @var list */ + public array $list3 = []; + + /** @var list */ + public array $list4 = []; + + /** @var list */ + public array $list5 = []; + + /** @var list */ + public array $list6 = []; + + /** @var list */ + public array $list7 = []; + + /** @var list */ + public array $list8 = []; + + /** @var list */ + public array $list9 = []; + + /** @var list */ + public array $loop1 = []; + + /** @var list */ + public array $loop2 = []; + + /** @var list */ + public array $loop3 = []; + +} + +/** + * Regression test for loop widening expanding a shape with optional keys into every variant. + * + * Nine conditional writes give $values nine optional keys, and the append in each loop makes + * the loop's key optional too. Widening the loop's scope flattened both sides with + * TypeUtils::flattenTypes(), which turns a shape with N optional keys into its 2^N concrete + * variants, only for the union right after to merge the thousand of them back into the same + * shape pair by pair. MutatingScope::generalizeType() now splits only unions. + * + * `bin/phpstan analyse -l 8 --debug` on this file: 4.6 s on 2.3.x, 1.5 s with the fix. + */ +final class Analysis +{ + + /** + * @return array> + */ + public function convert1(Answer $answer): array + { + $values = ['fields' => ['answer']]; + if ($answer->list1 !== []) { + $values['list1'] = array_map(static fn (string $value): string => strtolower($value), $answer->list1); + } + if ($answer->list2 !== []) { + $values['list2'] = array_map(static fn (string $value): string => strtolower($value), $answer->list2); + } + if ($answer->list3 !== []) { + $values['list3'] = array_map(static fn (string $value): string => strtolower($value), $answer->list3); + } + if ($answer->list4 !== []) { + $values['list4'] = array_map(static fn (string $value): string => strtolower($value), $answer->list4); + } + if ($answer->list5 !== []) { + $values['list5'] = array_map(static fn (string $value): string => strtolower($value), $answer->list5); + } + if ($answer->list6 !== []) { + $values['list6'] = array_map(static fn (string $value): string => strtolower($value), $answer->list6); + } + if ($answer->list7 !== []) { + $values['list7'] = array_map(static fn (string $value): string => strtolower($value), $answer->list7); + } + if ($answer->list8 !== []) { + $values['list8'] = array_map(static fn (string $value): string => strtolower($value), $answer->list8); + } + if ($answer->list9 !== []) { + $values['list9'] = array_map(static fn (string $value): string => strtolower($value), $answer->list9); + } + + foreach ($answer->loop1 as $value) { + if ($value !== '') { + $values['items'][] = $value; + } + } + foreach ($answer->loop2 as $value) { + if ($value !== '') { + $values['items'][] = $value; + } + } + foreach ($answer->loop3 as $value) { + if ($value !== '') { + $values['items'][] = $value; + } + } + + return $values; + } + + /** + * @return array> + */ + public function convert2(Answer $answer): array + { + $values = ['fields' => ['answer']]; + if ($answer->list1 !== []) { + $values['list1'] = array_map(static fn (string $value): string => strtolower($value), $answer->list1); + } + if ($answer->list2 !== []) { + $values['list2'] = array_map(static fn (string $value): string => strtolower($value), $answer->list2); + } + if ($answer->list3 !== []) { + $values['list3'] = array_map(static fn (string $value): string => strtolower($value), $answer->list3); + } + if ($answer->list4 !== []) { + $values['list4'] = array_map(static fn (string $value): string => strtolower($value), $answer->list4); + } + if ($answer->list5 !== []) { + $values['list5'] = array_map(static fn (string $value): string => strtolower($value), $answer->list5); + } + if ($answer->list6 !== []) { + $values['list6'] = array_map(static fn (string $value): string => strtolower($value), $answer->list6); + } + if ($answer->list7 !== []) { + $values['list7'] = array_map(static fn (string $value): string => strtolower($value), $answer->list7); + } + if ($answer->list8 !== []) { + $values['list8'] = array_map(static fn (string $value): string => strtolower($value), $answer->list8); + } + if ($answer->list9 !== []) { + $values['list9'] = array_map(static fn (string $value): string => strtolower($value), $answer->list9); + } + + foreach ($answer->loop1 as $value) { + if ($value !== '') { + $values['items'][] = $value; + } + } + foreach ($answer->loop2 as $value) { + if ($value !== '') { + $values['items'][] = $value; + } + } + foreach ($answer->loop3 as $value) { + if ($value !== '') { + $values['items'][] = $value; + } + } + + return $values; + } + + /** + * @return array> + */ + public function convert3(Answer $answer): array + { + $values = ['fields' => ['answer']]; + if ($answer->list1 !== []) { + $values['list1'] = array_map(static fn (string $value): string => strtolower($value), $answer->list1); + } + if ($answer->list2 !== []) { + $values['list2'] = array_map(static fn (string $value): string => strtolower($value), $answer->list2); + } + if ($answer->list3 !== []) { + $values['list3'] = array_map(static fn (string $value): string => strtolower($value), $answer->list3); + } + if ($answer->list4 !== []) { + $values['list4'] = array_map(static fn (string $value): string => strtolower($value), $answer->list4); + } + if ($answer->list5 !== []) { + $values['list5'] = array_map(static fn (string $value): string => strtolower($value), $answer->list5); + } + if ($answer->list6 !== []) { + $values['list6'] = array_map(static fn (string $value): string => strtolower($value), $answer->list6); + } + if ($answer->list7 !== []) { + $values['list7'] = array_map(static fn (string $value): string => strtolower($value), $answer->list7); + } + if ($answer->list8 !== []) { + $values['list8'] = array_map(static fn (string $value): string => strtolower($value), $answer->list8); + } + if ($answer->list9 !== []) { + $values['list9'] = array_map(static fn (string $value): string => strtolower($value), $answer->list9); + } + + foreach ($answer->loop1 as $value) { + if ($value !== '') { + $values['items'][] = $value; + } + } + foreach ($answer->loop2 as $value) { + if ($value !== '') { + $values['items'][] = $value; + } + } + foreach ($answer->loop3 as $value) { + if ($value !== '') { + $values['items'][] = $value; + } + } + + return $values; + } + + /** + * @return array> + */ + public function convert4(Answer $answer): array + { + $values = ['fields' => ['answer']]; + if ($answer->list1 !== []) { + $values['list1'] = array_map(static fn (string $value): string => strtolower($value), $answer->list1); + } + if ($answer->list2 !== []) { + $values['list2'] = array_map(static fn (string $value): string => strtolower($value), $answer->list2); + } + if ($answer->list3 !== []) { + $values['list3'] = array_map(static fn (string $value): string => strtolower($value), $answer->list3); + } + if ($answer->list4 !== []) { + $values['list4'] = array_map(static fn (string $value): string => strtolower($value), $answer->list4); + } + if ($answer->list5 !== []) { + $values['list5'] = array_map(static fn (string $value): string => strtolower($value), $answer->list5); + } + if ($answer->list6 !== []) { + $values['list6'] = array_map(static fn (string $value): string => strtolower($value), $answer->list6); + } + if ($answer->list7 !== []) { + $values['list7'] = array_map(static fn (string $value): string => strtolower($value), $answer->list7); + } + if ($answer->list8 !== []) { + $values['list8'] = array_map(static fn (string $value): string => strtolower($value), $answer->list8); + } + if ($answer->list9 !== []) { + $values['list9'] = array_map(static fn (string $value): string => strtolower($value), $answer->list9); + } + + foreach ($answer->loop1 as $value) { + if ($value !== '') { + $values['items'][] = $value; + } + } + foreach ($answer->loop2 as $value) { + if ($value !== '') { + $values['items'][] = $value; + } + } + foreach ($answer->loop3 as $value) { + if ($value !== '') { + $values['items'][] = $value; + } + } + + return $values; + } + +} From faf58dc8c6dfa8c39a22d6785d3c87936c523ec1 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Mon, 14 Sep 2026 19:01:07 +0200 Subject: [PATCH 7/7] Run the NoDiscard rule tests wherever their syntax parses 76f47ddb80 dropped the PHP 8.5 requirement from the three NoDiscard rule tests, but their fixtures still use the pipe operator and the (void) cast, which are PHP 8.5 syntax - on the PHP 7.4 job the pipe token cannot even be lexed. Each fixture is split: the plain calls stay in the original file and run on every PHP with attributes (7.4 reads #[\NoDiscard] as a comment, so nothing would be reported there), the (void) casts and pipes move to a -php85 fixture behind #[RequiresPhp('>= 8.5.0')]. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01DfQHLTyyoMfjfa4sXJCGa5 --- ...FunctionStatementWithNoDiscardRuleTest.php | 43 ++++++++++++------- ...-call-statement-result-discarded-php85.php | 30 +++++++++++++ ...nction-call-statement-result-discarded.php | 16 +------ ...ToMethodStatementWithNoDiscardRuleTest.php | 33 +++++++++----- ...icMethodStatementWithNoDiscardRuleTest.php | 33 +++++++++----- ...-call-statement-result-discarded-php85.php | 37 ++++++++++++++++ ...method-call-statement-result-discarded.php | 16 +------ ...-call-statement-result-discarded-php85.php | 33 ++++++++++++++ ...method-call-statement-result-discarded.php | 15 +------ 9 files changed, 174 insertions(+), 82 deletions(-) create mode 100644 tests/PHPStan/Rules/Functions/data/function-call-statement-result-discarded-php85.php create mode 100644 tests/PHPStan/Rules/Methods/data/method-call-statement-result-discarded-php85.php create mode 100644 tests/PHPStan/Rules/Methods/data/static-method-call-statement-result-discarded-php85.php diff --git a/tests/PHPStan/Rules/Functions/CallToFunctionStatementWithNoDiscardRuleTest.php b/tests/PHPStan/Rules/Functions/CallToFunctionStatementWithNoDiscardRuleTest.php index 2c8fab46fb6..0475ab9d394 100644 --- a/tests/PHPStan/Rules/Functions/CallToFunctionStatementWithNoDiscardRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallToFunctionStatementWithNoDiscardRuleTest.php @@ -4,6 +4,7 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +use PHPUnit\Framework\Attributes\RequiresPhp; /** * @extends RuleTestCase @@ -16,6 +17,8 @@ protected function getRule(): Rule return new CallToFunctionStatementWithNoDiscardRule(self::createReflectionProvider()); } + // #[\NoDiscard] is an attribute, a comment on PHP 7.4 + #[RequiresPhp('>= 8.0.0')] public function testRule(): void { $this->analyse([__DIR__ . '/data/function-call-statement-result-discarded.php'], [ @@ -25,47 +28,55 @@ public function testRule(): void ], [ 'Call to function FunctionCallStatementResultDiscarded\differentCase() on a separate line discards return value.', - 25, + 23, ], [ 'Call to callable \'FunctionCallStateme…\' on a separate line discards return value.', - 30, + 28, ], [ 'Call to callable Closure(int): array on a separate line discards return value.', - 35, + 33, ], [ 'Call to callable Closure(): 1 on a separate line discards return value.', - 40, + 38, ], [ 'Call to callable Closure(): 1 on a separate line discards return value.', - 45, + 43, ], + ]); + } + + // the (void) cast and the pipe operator are PHP 8.5 syntax + #[RequiresPhp('>= 8.5.0')] + public function testRulePhp85(): void + { + $this->analyse([__DIR__ . '/data/function-call-statement-result-discarded-php85.php'], [ [ - 'Call to function FunctionCallStatementResultDiscarded\canDiscard() in (void) cast but function allows discarding return value.', - 55, + 'Call to function FunctionCallStatementResultDiscardedPhp85\canDiscard() in (void) cast but function allows discarding return value.', + 17, ], [ 'Call to callable \'FunctionCallStateme…\' in (void) cast but callable allows discarding return value.', - 59, + 20, ], [ - 'Call to function FunctionCallStatementResultDiscarded\withSideEffects() on a separate line discards return value.', - 61, + 'Call to function FunctionCallStatementResultDiscardedPhp85\withSideEffects() on a separate line discards return value.', + 22, ], [ - 'Call to function FunctionCallStatementResultDiscarded\canDiscard() in (void) cast but function allows discarding return value.', - 64, + 'Call to function FunctionCallStatementResultDiscardedPhp85\canDiscard() in (void) cast but function allows discarding return value.', + 25, ], [ - 'Call to function FunctionCallStatementResultDiscarded\withSideEffects() on a separate line discards return value.', - 66, + 'Call to function FunctionCallStatementResultDiscardedPhp85\withSideEffects() on a separate line discards return value.', + 27, ], [ - 'Call to function FunctionCallStatementResultDiscarded\canDiscard() in (void) cast but function allows discarding return value.', - 69, + 'Call to function FunctionCallStatementResultDiscardedPhp85\canDiscard() in (void) cast but function allows discarding return value.', + 30, ], ]); } diff --git a/tests/PHPStan/Rules/Functions/data/function-call-statement-result-discarded-php85.php b/tests/PHPStan/Rules/Functions/data/function-call-statement-result-discarded-php85.php new file mode 100644 index 00000000000..a01feea8fe1 --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/function-call-statement-result-discarded-php85.php @@ -0,0 +1,30 @@ += 8.5 + +namespace FunctionCallStatementResultDiscardedPhp85; + +#[\NoDiscard] +function withSideEffects(int $i): array { + echo __FUNCTION__ . "\n"; + return [1]; +} + +function canDiscard(int $i): int +{ + return 1; +} + +(void)withSideEffects(5); +(void) canDiscard(5); + +$canDiscardCb = 'FunctionCallStatementResultDiscardedPhp85\\canDiscard'; +(void) $canDiscardCb(); + +5 |> withSideEffects(...); +5 |> canDiscard(...); +(void) 5 |> withSideEffects(...); +(void) 5 |> canDiscard(...); + +5 |> (fn ($x) => withSideEffects($x)); +5 |> (fn ($x) => canDiscard($x)); +(void) 5 |> (fn ($x) => withSideEffects($x)); +(void) 5 |> (fn ($x) => canDiscard($x)); diff --git a/tests/PHPStan/Rules/Functions/data/function-call-statement-result-discarded.php b/tests/PHPStan/Rules/Functions/data/function-call-statement-result-discarded.php index a7fa4c8b1e8..ca6504b267c 100644 --- a/tests/PHPStan/Rules/Functions/data/function-call-statement-result-discarded.php +++ b/tests/PHPStan/Rules/Functions/data/function-call-statement-result-discarded.php @@ -1,4 +1,4 @@ -= 8.5 += 8.1 namespace FunctionCallStatementResultDiscarded; @@ -10,8 +10,6 @@ function withSideEffects(int $i): array { withSideEffects(5); -(void)withSideEffects(5); - foreach (withSideEffects(5) as $num) { var_dump($num); } @@ -52,18 +50,6 @@ function canDiscard(int $i): int } canDiscard(5); -(void) canDiscard(5); $canDiscardCb = 'FunctionCallStatementResultDiscarded\\canDiscard'; $canDiscardCb(); -(void) $canDiscardCb(); - -5 |> withSideEffects(...); -5 |> canDiscard(...); -(void) 5 |> withSideEffects(...); -(void) 5 |> canDiscard(...); - -5 |> (fn ($x) => withSideEffects($x)); -5 |> (fn ($x) => canDiscard($x)); -(void) 5 |> (fn ($x) => withSideEffects($x)); -(void) 5 |> (fn ($x) => canDiscard($x)); diff --git a/tests/PHPStan/Rules/Methods/CallToMethodStatementWithNoDiscardRuleTest.php b/tests/PHPStan/Rules/Methods/CallToMethodStatementWithNoDiscardRuleTest.php index c7be0ca590f..4443372a2cf 100644 --- a/tests/PHPStan/Rules/Methods/CallToMethodStatementWithNoDiscardRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallToMethodStatementWithNoDiscardRuleTest.php @@ -5,6 +5,7 @@ use PHPStan\Rules\Rule; use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; +use PHPUnit\Framework\Attributes\RequiresPhp; /** * @extends RuleTestCase @@ -28,6 +29,8 @@ protected function getRule(): Rule ); } + // #[\NoDiscard] is an attribute, a comment on PHP 7.4 + #[RequiresPhp('>= 8.0.0')] public function testRule(): void { $this->analyse([__DIR__ . '/data/method-call-statement-result-discarded.php'], [ @@ -41,27 +44,35 @@ public function testRule(): void ], [ 'Call to method MethodCallStatementResultDiscarded\ClassWithInstanceSideEffects::differentCase() on a separate line discards return value.', - 30, + 27, ], + ]); + } + + // the (void) cast and the pipe operator are PHP 8.5 syntax + #[RequiresPhp('>= 8.5.0')] + public function testRulePhp85(): void + { + $this->analyse([__DIR__ . '/data/method-call-statement-result-discarded-php85.php'], [ [ - 'Call to method MethodCallStatementResultDiscarded\Foo::canDiscard() in (void) cast but method allows discarding return value.', - 45, + 'Call to method MethodCallStatementResultDiscardedPhp85\Foo::canDiscard() in (void) cast but method allows discarding return value.', + 27, ], [ - 'Call to method MethodCallStatementResultDiscarded\ClassWithInstanceSideEffects::instanceMethod() on a separate line discards return value.', - 47, + 'Call to method MethodCallStatementResultDiscardedPhp85\ClassWithInstanceSideEffects::instanceMethod() on a separate line discards return value.', + 29, ], [ - 'Call to method MethodCallStatementResultDiscarded\Foo::canDiscard() in (void) cast but method allows discarding return value.', - 50, + 'Call to method MethodCallStatementResultDiscardedPhp85\Foo::canDiscard() in (void) cast but method allows discarding return value.', + 32, ], [ - 'Call to method MethodCallStatementResultDiscarded\ClassWithInstanceSideEffects::instanceMethod() on a separate line discards return value.', - 52, + 'Call to method MethodCallStatementResultDiscardedPhp85\ClassWithInstanceSideEffects::instanceMethod() on a separate line discards return value.', + 34, ], [ - 'Call to method MethodCallStatementResultDiscarded\Foo::canDiscard() in (void) cast but method allows discarding return value.', - 55, + 'Call to method MethodCallStatementResultDiscardedPhp85\Foo::canDiscard() in (void) cast but method allows discarding return value.', + 37, ], ]); } diff --git a/tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithNoDiscardRuleTest.php b/tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithNoDiscardRuleTest.php index fd53633625e..b304a00c21a 100644 --- a/tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithNoDiscardRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithNoDiscardRuleTest.php @@ -5,6 +5,7 @@ use PHPStan\Rules\Rule; use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; +use PHPUnit\Framework\Attributes\RequiresPhp; /** * @extends RuleTestCase @@ -30,6 +31,8 @@ protected function getRule(): Rule ); } + // #[\NoDiscard] is an attribute, a comment on PHP 7.4 + #[RequiresPhp('>= 8.0.0')] public function testRule(): void { $this->analyse([__DIR__ . '/data/static-method-call-statement-result-discarded.php'], [ @@ -39,27 +42,35 @@ public function testRule(): void ], [ 'Call to static method StaticMethodCallStatementResultDiscarded\ClassWithStaticSideEffects::differentCase() on a separate line discards return value.', - 27, + 25, ], + ]); + } + + // the (void) cast and the pipe operator are PHP 8.5 syntax + #[RequiresPhp('>= 8.5.0')] + public function testRulePhp85(): void + { + $this->analyse([__DIR__ . '/data/static-method-call-statement-result-discarded-php85.php'], [ [ - 'Call to static method StaticMethodCallStatementResultDiscarded\Foo::canDiscard() in (void) cast but method allows discarding return value.', - 41, + 'Call to static method StaticMethodCallStatementResultDiscardedPhp85\Foo::canDiscard() in (void) cast but method allows discarding return value.', + 23, ], [ - 'Call to static method StaticMethodCallStatementResultDiscarded\ClassWithStaticSideEffects::staticMethod() on a separate line discards return value.', - 43, + 'Call to static method StaticMethodCallStatementResultDiscardedPhp85\ClassWithStaticSideEffects::staticMethod() on a separate line discards return value.', + 25, ], [ - 'Call to static method StaticMethodCallStatementResultDiscarded\Foo::canDiscard() in (void) cast but method allows discarding return value.', - 46, + 'Call to static method StaticMethodCallStatementResultDiscardedPhp85\Foo::canDiscard() in (void) cast but method allows discarding return value.', + 28, ], [ - 'Call to static method StaticMethodCallStatementResultDiscarded\ClassWithStaticSideEffects::staticMethod() on a separate line discards return value.', - 48, + 'Call to static method StaticMethodCallStatementResultDiscardedPhp85\ClassWithStaticSideEffects::staticMethod() on a separate line discards return value.', + 30, ], [ - 'Call to static method StaticMethodCallStatementResultDiscarded\Foo::canDiscard() in (void) cast but method allows discarding return value.', - 51, + 'Call to static method StaticMethodCallStatementResultDiscardedPhp85\Foo::canDiscard() in (void) cast but method allows discarding return value.', + 33, ], ]); } diff --git a/tests/PHPStan/Rules/Methods/data/method-call-statement-result-discarded-php85.php b/tests/PHPStan/Rules/Methods/data/method-call-statement-result-discarded-php85.php new file mode 100644 index 00000000000..e0320d9050f --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/method-call-statement-result-discarded-php85.php @@ -0,0 +1,37 @@ += 8.5 + +namespace MethodCallStatementResultDiscardedPhp85; + +class ClassWithInstanceSideEffects { + #[\NoDiscard] + public function instanceMethod(): array { + echo __METHOD__ . "\n"; + return [2]; + } +} + +class Foo +{ + + public function canDiscard(): array { + return []; + } + +} + +$o = new ClassWithInstanceSideEffects(); +$foo = new Foo(); + +(void)$o->instanceMethod(); +(void)$o?->instanceMethod(); +(void) $foo->canDiscard(); + +5 |> $o->instanceMethod(...); +5 |> $foo->canDiscard(...); +(void) 5 |> $o->instanceMethod(...); +(void) 5 |> $foo->canDiscard(...); + +5 |> (fn ($x) => $o->instanceMethod($x)); +5 |> (fn ($x) => $foo->canDiscard($x)); +(void) 5 |> (fn ($x) => $o->instanceMethod($x)); +(void) 5 |> (fn ($x) => $foo->canDiscard($x)); diff --git a/tests/PHPStan/Rules/Methods/data/method-call-statement-result-discarded.php b/tests/PHPStan/Rules/Methods/data/method-call-statement-result-discarded.php index 194f9753ff7..4919dade33d 100644 --- a/tests/PHPStan/Rules/Methods/data/method-call-statement-result-discarded.php +++ b/tests/PHPStan/Rules/Methods/data/method-call-statement-result-discarded.php @@ -1,4 +1,4 @@ -= 8.5 += 8.1 namespace MethodCallStatementResultDiscarded; @@ -20,9 +20,6 @@ public function differentCase(): array { $o->instanceMethod(); $o?->instanceMethod(); -(void)$o->instanceMethod(); -(void)$o?->instanceMethod(); - foreach ($o->instanceMethod() as $num) { var_dump($num); } @@ -42,14 +39,3 @@ public function canDiscard(): array { $foo = new Foo(); $foo->canDiscard(); -(void) $foo->canDiscard(); - -5 |> $o->instanceMethod(...); -5 |> $foo->canDiscard(...); -(void) 5 |> $o->instanceMethod(...); -(void) 5 |> $foo->canDiscard(...); - -5 |> (fn ($x) => $o->instanceMethod($x)); -5 |> (fn ($x) => $foo->canDiscard($x)); -(void) 5 |> (fn ($x) => $o->instanceMethod($x)); -(void) 5 |> (fn ($x) => $foo->canDiscard($x)); diff --git a/tests/PHPStan/Rules/Methods/data/static-method-call-statement-result-discarded-php85.php b/tests/PHPStan/Rules/Methods/data/static-method-call-statement-result-discarded-php85.php new file mode 100644 index 00000000000..8cc7cbc472f --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/static-method-call-statement-result-discarded-php85.php @@ -0,0 +1,33 @@ += 8.5 + +namespace StaticMethodCallStatementResultDiscardedPhp85; + +class ClassWithStaticSideEffects { + #[\NoDiscard] + public static function staticMethod(): array { + echo __METHOD__ . "\n"; + return [2]; + } +} + +class Foo +{ + + public static function canDiscard(): array { + return []; + } + +} + +(void)ClassWithStaticSideEffects::staticMethod(); +(void) Foo::canDiscard(); + +5 |> ClassWithStaticSideEffects::staticMethod(...); +5 |> Foo::canDiscard(...); +(void) 5 |> ClassWithStaticSideEffects::staticMethod(...); +(void) 5 |> Foo::canDiscard(...); + +5 |> (fn ($x) => ClassWithStaticSideEffects::staticMethod($x)); +5 |> (fn ($x) => Foo::canDiscard($x)); +(void) 5 |> (fn ($x) => ClassWithStaticSideEffects::staticMethod($x)); +(void) 5 |> (fn ($x) => Foo::canDiscard($x)); diff --git a/tests/PHPStan/Rules/Methods/data/static-method-call-statement-result-discarded.php b/tests/PHPStan/Rules/Methods/data/static-method-call-statement-result-discarded.php index d717446d7e2..8bcf4b2da51 100644 --- a/tests/PHPStan/Rules/Methods/data/static-method-call-statement-result-discarded.php +++ b/tests/PHPStan/Rules/Methods/data/static-method-call-statement-result-discarded.php @@ -1,4 +1,4 @@ -= 8.5 += 8.1 namespace StaticMethodCallStatementResultDiscarded; @@ -18,8 +18,6 @@ public static function differentCase(): array { ClassWithStaticSideEffects::staticMethod(); -(void)ClassWithStaticSideEffects::staticMethod(); - foreach (ClassWithStaticSideEffects::staticMethod() as $num) { var_dump($num); } @@ -38,14 +36,3 @@ public static function canDiscard(): array { } Foo::canDiscard(); -(void) Foo::canDiscard(); - -5 |> ClassWithStaticSideEffects::staticMethod(...); -5 |> Foo::canDiscard(...); -(void) 5 |> ClassWithStaticSideEffects::staticMethod(...); -(void) 5 |> Foo::canDiscard(...); - -5 |> (fn ($x) => ClassWithStaticSideEffects::staticMethod($x)); -5 |> (fn ($x) => Foo::canDiscard($x)); -(void) 5 |> (fn ($x) => ClassWithStaticSideEffects::staticMethod($x)); -(void) 5 |> (fn ($x) => Foo::canDiscard($x));