{"record":{"id":"f7472951dde73e4a","repo":"PHPOffice/PhpSpreadsheet","slug":"invalid-operation-for-blanks-cf-rule-wizard","errorCode":null,"errorMessage":"Invalid Operation for Blanks CF Rule Wizard","messagePattern":"Invalid Operation for Blanks CF Rule Wizard","errorType":"exception","errorClass":"PhpOffice\\PhpSpreadsheet\\Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Style/ConditionalFormatting/Wizard/Blanks.php","lineNumber":88,"sourceCode":"        ) {\n            throw new Exception('Conditional is not a Blanks CF Rule conditional');\n        }\n\n        $wizard = new self($cellRange);\n        $wizard->style = $conditional->getStyle();\n        $wizard->stopIfTrue = $conditional->getStopIfTrue();\n        $wizard->inverse = $conditional->getConditionType() === Conditional::CONDITION_CONTAINSBLANKS;\n\n        return $wizard;\n    }\n\n    /**\n     * @param mixed[] $arguments\n     */\n    public function __call(string $methodName, array $arguments): self\n    {\n        if (!array_key_exists($methodName, self::OPERATORS)) {\n            throw new Exception('Invalid Operation for Blanks CF Rule Wizard');\n        }\n\n        $this->inverse(self::OPERATORS[$methodName]);\n\n        return $this;\n    }\n}\n","sourceCodeStart":70,"sourceCodeEnd":96,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Style/ConditionalFormatting/Wizard/Blanks.php#L70-L96","documentation":"The Blanks wizard exposes its operators through __call: every invocation is checked against a fixed OPERATORS map whose only keys are 'isBlank', 'empty', 'notBlank' and 'notEmpty'. Any other method name throws. Note the trap: the class docblock advertises isEmpty(), but the runtime map contains 'empty', so ->isEmpty() throws while ->empty() and ->isBlank() work.","triggerScenarios":"Calling ->isEmpty() (the docblock name that has no runtime key); case-mismatched names like ->notblank() or ->IsBlank(); guessed names such as ->isNotEmpty() or ->blank().","commonSituations":"IDE autocompletion picking the docblock's isEmpty(); developers assuming symmetric naming with other wizards; fluent chains built dynamically from user-supplied operator names.","solutions":["Use only isBlank(), empty(), notBlank(), notEmpty()","Prefer isBlank()/notBlank() - they are unambiguous and match the other wizards' style","Validate dynamically chosen method names against the allowed list before invoking","Catch PhpSpreadsheetException around dynamic calls to fail softly"],"exampleFix":"// before\n$blanksWizard = (new Wizard('A1:E10'))->newRule(Wizard::BLANKS);\n$blanksWizard->isEmpty();   // throws: runtime operator key is 'empty', not 'isEmpty'\n\n// after\n$blanksWizard->isBlank();   // or ->empty(), ->notBlank(), ->notEmpty()","handlingStrategy":"validation","validationCode":"$allowed = ['isBlank', 'empty', 'notBlank', 'notEmpty'];\n$method = $config['blankOperator'] ?? 'isBlank';\nif (!in_array($method, $allowed, true)) {\n    throw new InvalidArgumentException('Unknown Blanks operator: ' . $method);\n}\n$wizard->$method();","typeGuard":null,"tryCatchPattern":"use PhpOffice\\PhpSpreadsheet\\Exception as PhpSpreadsheetException;\n\ntry {\n    $wizard->$method();\n} catch (PhpSpreadsheetException $e) {\n    // $method is not one of isBlank/empty/notBlank/notEmpty\n    throw new InvalidArgumentException('Invalid blank operator: ' . $method, 0, $e);\n}","preventionTips":["Use only isBlank(), empty(), notBlank(), notEmpty() on Blanks wizards","Do not trust the docblock's isEmpty() - the runtime key is 'empty'","Prefer isBlank()/notBlank() for clarity","Validate operator names against a whitelist whenever they arrive from config or user input"],"tags":["php","phpspreadsheet","conditional-formatting","wizard","magic-methods","fluent-interface","blanks"],"backgroundTag":"invalid-fluent-builder-method","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}