You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 16:27:46