3

Are PHP8.1 read-only properties compatible with bind_param?

Here is my constructor

public function __construct(
    private readonly ?bool $alreadyLive, //If true, the article is already live and will be updated. If false, it is a new article
    private readonly bool $pushLive, //If true, the article will be pushed live. If false, it will be saved in 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;
}

I'm attempting to insert some data into a database like so:

    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) {
        //Rollback the transaction
        $connection->rollback();

        //Return error message
        $response['status'] = 'error';
        $response['message'] = 'There was an error submitting your article. Please try again.';
        return $response;
    }

But I keep getting this error:

Cannot modify readonly property article::$authorID

Which is caused by this line as per the line in the stack trace:

$stmt->bind_param("sisssiiss", $this->articleTitle, $this->authorID, $this->articleContent, $this->articleExcerpt, $this->imageCard, $views, $this->heroPosition, $this->articleType, $this->articleStatus);
Dharman
  • 30,962
  • 25
  • 85
  • 135
GenesisBits
  • 364
  • 2
  • 23
  • The lines are read only, so accessing them like you do in your bind_param should be fine. That line sounds like you're trying to modify authorID somewhere. The full stack trace or error message will tell you exactly where the error is coming from. – aynber May 11 '23 at 14:15
  • 2
    that's interesting bug that need to be considered by the language devs. As a workaround you can wrap your variables into `...[]`, i.e. `$stmt->bind_param("sisssiiss", ...[$this->articleTitle,...])` – Your Common Sense May 11 '23 at 14:25

1 Answers1

5

The error is absolutely correct. You cannot modify readonly properties, but you also cannot use them in a write context. In PHP, passing parameters by reference is considered a read-write operation. Thus you are not allowed to pass readonly properties to bind_param() just as you are not allowed to pass constants or literals.

To overcome this problem, use execute() and pass the values as an array.

$stmt = $mysqli->prepare();
$stmt->execute([
    $this->articleTitle,
    // ...
]);

Or since PHP 8.2, you can use execute_query():

$mysqli->execute_query($sqlQuery, [
    $this->articleTitle,
    // ...
]);
Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
Dharman
  • 30,962
  • 25
  • 85
  • 135