PHP8.1只读属性与mysqli bind_param兼容吗?绑定参数时报错求解
PHP 8.1 只读属性与 bind_param 兼容吗?
问题场景
我的类构造函数定义了多个只读属性:
public function __construct( private readonly ?bool $alreadyLive, // 为true时表示文章已发布,将执行更新;为false时是新文章 private readonly bool $pushLive, // 为true时文章将发布;为false时保存到pending_articles表 private string $articleTitle, private string $articleExcerpt, private string $articleContent, private string $imageCard, private readonly string $articleType, private readonly string $articleStatus, private readonly ?int $articleNumber, private readonly int $authorID, private readonly int $heroPosition, databaseconnection $db ) { $this->db = $db; }
尝试用以下代码向数据库插入数据时:
try { $sql = "INSERT INTO " . $table . " (title, author, content, excerpt, image_card, views, hero_position, type, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; $stmt = $connection->prepare($sql); $stmt->bind_param("sisssiiss", $this->articleTitle, $this->authorID, $this->articleContent, $this->articleExcerpt, $this->imageCard, $views, $this->heroPosition, $this->articleType, $this->articleStatus ); $stmt->execute(); $article_id = $stmt->insert_id; $stmt->close(); } catch (\Exception) { // 回滚事务 $connection->rollback(); // 返回错误信息 $response['status'] = 'error'; $response['message'] = '提交文章时出错,请重试。'; return $response; }
持续报错:
Cannot modify readonly property article::$authorID
堆栈跟踪显示错误来自bind_param的调用行。
原因与解决方案
原因
mysqli_stmt::bind_param方法要求参数以引用传递,而PHP 8.1的只读属性禁止任何形式的修改(包括引用传递时内部的写操作尝试,哪怕实际不会修改值),因此触发了只读属性的保护机制,抛出错误。
解决方案
将只读属性的值先赋值给普通的可写变量,再把这些临时变量传给bind_param即可:
try { $sql = "INSERT INTO " . $table . " (title, author, content, excerpt, image_card, views, hero_position, type, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; $stmt = $connection->prepare($sql); // 把只读属性的值复制到临时变量 $tempAuthorID = $this->authorID; $tempHeroPosition = $this->heroPosition; $tempArticleType = $this->articleType; $tempArticleStatus = $this->articleStatus; // 使用临时变量绑定参数 $stmt->bind_param("sisssiiss", $this->articleTitle, $tempAuthorID, $this->articleContent, $this->articleExcerpt, $this->imageCard, $views, $tempHeroPosition, $tempArticleType, $tempArticleStatus ); $stmt->execute(); $article_id = $stmt->insert_id; $stmt->close(); } catch (\Exception) { // 回滚事务 $connection->rollback(); // 返回错误信息 $response['status'] = 'error'; $response['message'] = '提交文章时出错,请重试。'; return $response; }
这样既保留了只读属性的封装特性,又满足了bind_param对参数的要求,避免了报错。
内容的提问来源于stack exchange,提问作者GenesisBits
相关产品推荐
相关产品推荐

