{"record":{"id":"dd60ab4915a03fcd","repo":"yiisoft/yii2","slug":"getting-write-only-property-get-class-this","errorCode":null,"errorMessage":"'Getting write-only property: ' . get_class($this) . '::' . $name","messagePattern":"'Getting write-only property: ' \\. get_class\\(\\$this\\) \\. '::' \\. \\$name","errorType":"exception","errorClass":"InvalidCallException","httpStatus":null,"severity":"error","filePath":"framework/base/BaseObject.php","lineNumber":139,"sourceCode":"\n    /**\n     * Returns the value of an object property.\n     *\n     * Do not call this method directly as it is a PHP magic method that\n     * will be implicitly called when executing `$value = $object->property;`.\n     * @param string $name the property name\n     * @return mixed the property value\n     * @throws UnknownPropertyException if the property is not defined\n     * @throws InvalidCallException if the property is write-only\n     * @see __set()\n     */\n    public function __get($name)\n    {\n        $getter = 'get' . $name;\n        if (method_exists($this, $getter)) {\n            return $this->$getter();\n        } elseif (method_exists($this, 'set' . $name)) {\n            throw new InvalidCallException('Getting write-only property: ' . get_class($this) . '::' . $name);\n        }\n\n        throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);\n    }\n\n    /**\n     * Sets value of an object property.\n     *\n     * Do not call this method directly as it is a PHP magic method that\n     * will be implicitly called when executing `$object->property = $value;`.\n     * @param string $name the property name or the event name\n     * @param mixed $value the property value\n     * @throws UnknownPropertyException if the property is not defined\n     * @throws InvalidCallException if the property is read-only\n     * @see __get()\n     */\n    public function __set($name, $value)\n    {","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/yiisoft/yii2/blob/66f00d18a29b520f85e8e8f1e32d1e7e7b556cac/framework/base/BaseObject.php#L121-L157","documentation":"yii\\base\\BaseObject implements properties via magic methods: __get() looks for a getXxx() method, then a setXxx() method. If only a setter exists the property is write-only by design, and reading it throws InvalidCallException('Getting write-only property: ...'). The class author exposed mutation but deliberately (or accidentally) provided no read path.","triggerScenarios":"echo $object->apiKey when only setApiKey() exists; reading configuration-holder properties of a component that accepts injection but stores the value internally; a getter removed during a major-version refactor while the setter remained.","commonSituations":"Configuration objects that are write-only by design; secret/token holders where reading is intentionally blocked; API drift after upgrading a vendor package.","solutions":["Read the class source: a differently-named getter (e.g. getTokenValue()) often exposes the same data","If you own the class, add public function getX() { return $this->_x; }","Otherwise stop reading the property - treat it as an input, not as observable state"],"exampleFix":"// before\nclass TokenStore extends \\yii\\base\\BaseObject\n{\n    private $_key;\n    public function setKey($k) { $this->_key = $k; }\n}\n$value = $store->key; // InvalidCallException: Getting write-only property\n\n// after\npublic function getKey() { return $this->_key; }\n$value = $store->key;","handlingStrategy":"type-guard","validationCode":"if ($object->canGetProperty($name)) {\n    $value = $object->$name;\n} else {\n    $value = null; // property is write-only or absent\n}","typeGuard":"function hasReadAccess(\\yii\\base\\BaseObject $object, string $name): bool\n{\n    return $object->canGetProperty($name);\n}","tryCatchPattern":"try {\n    $value = $object->$name;\n} catch (\\yii\\base\\InvalidCallException $e) {\n    // 'Getting write-only property:' - use the setter-provided read API instead\n    Yii::warning($e->getMessage());\n    $value = null;\n}","preventionTips":["Annotate write-only properties with @property-write in docblocks so static analysis flags bad reads","Use canGetProperty() before dynamic property reads","Prefer paired getter/setter design for mutable configuration holders"],"tags":["oop","magic-methods","property-access"],"backgroundTag":"write-only-property-read","analyzedSha":"66f00d18a29b520f85e8e8f1e32d1e7e7b556cac","analyzedAt":"2026-08-17T05:17:23.470Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}