Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:129740 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by lists.php.net (Postfix) with ESMTPS id C0EBB1A00BC for ; Wed, 7 Jan 2026 18:32:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1767810761; bh=Wpy7x1EM8jOvjfmyLvWqx+8mXbrl4+jvGJZoDetodb4=; h=From:Date:Subject:To:From; b=diFRV0EpKPLw90rhDMH5kTFwAIFZAPTvkGYrD9PK/fRn8lmQpjjjpxumYIFKgIHEH PL1VSnxanLG35zI2BtxJ4/Hypg+Oo0qqdypG9VHVhm7vWrjfT3mmBG8mgALEUzyw7S L1PG2vqvK3OIkx65iJaI5nZHFTa31XNGcoDId7dxdZ0W2BZzQKIm8uTDlRlKKjSVzc +4DLNvlUlXx7qStaT6itfhODP2wgDWizy7QGhLux2tzyHzuOyFKHtiUK+0MVii6gTj U9LQGvblN/RRDAD12+PY4N+aZUodVjrPyBGBhw2g8v7O+CGhL7sri5DlY6W8GBad2w ryzqJlcu9dnPg== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 4E675180068 for ; Wed, 7 Jan 2026 18:32:40 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=0.6 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from mail-qv1-f49.google.com (mail-qv1-f49.google.com [209.85.219.49]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Wed, 7 Jan 2026 18:32:37 +0000 (UTC) Received: by mail-qv1-f49.google.com with SMTP id 6a1803df08f44-8887f43b224so29705076d6.1 for ; Wed, 07 Jan 2026 10:32:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1767810751; x=1768415551; darn=lists.php.net; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=sfBcr7kCR+oIO+CYrGNra9B9bXmOzbBzc7+Y+4Zef6M=; b=TQV78QXXrbxh36vj3cB033t2vhp8vi+2vwjKmIK0Dvp4Dzv2Xqix6uypdzZ5Rgww/i /hyKtTK0sIbcCccUyo4EIaD7/Azhx5JEJQpr702bD9N2nlUM05tC36uqsLoI28w51ptE ZwMRIToPicpYAbRfaoeGEoe8zYVSSz6ICrZSI8TT6vU/GaFN86s0Ti7v7AAvKFxx2reA o7Kv9DMxXSPFS1l7nYVAuMLlv9sRgF7wQtkYjtRP2a2sR10NZcZYK0/Hh2qbXG3nakku B0UzmxuVggF4qlAZW36vgS3Ve0jURFCz4RFJj+7TdnuNdylTmRFTt+w2cwPIvjF98GdC Ctaw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767810751; x=1768415551; h=to:subject:message-id:date:from:mime-version:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=sfBcr7kCR+oIO+CYrGNra9B9bXmOzbBzc7+Y+4Zef6M=; b=W6KRjmAUGgIcAiCBYThJIwl1bCaGEC8+e51HgkOao9A5kdbiwK6wq9aJTGlv/15/sd ++qqJBUd1rEGKo0pVOxBVwjrD0zKoGazZFHmLCeN7vdiA0rWSmuL5yDpGSCPgu47kswF vHoo9sfu8HBBsVO4GgIwda9CC07b1vjNKYLUvdH2IU4v3XdGi1wDi3EieyIBkMRf5kb8 CS4wGvGeupVVYueI+UcvPxm4FnEUn5z5hx5LrKCe1m8xjO1mGNqjPnWXyVsivd78QxEG Qtm7GinIX0PyOqVCLSXfVhrZOghWO9MK3Lx20EPYklLJMiAlejEnvLt0CtuN+h4knlfv H0Fg== X-Gm-Message-State: AOJu0YzPNI9NFX6Z1qJ++u2nVjH7fr87eUpyC79fim9t31BXV61lev/Z HR0yEukKY1ppUdvO7Lj9a/z98A2w1eDo/T5hKlEynkm4a659bFidWRGu42IYF6eywIDgW3/453I BHatE/m4YftzkP0FbuU2CHWFuDJEQXtU5+uCT X-Gm-Gg: AY/fxX5Yct5xNm0iFV9g0SiA1SKKPLJv2XcY8MIPOV9MNK1uYoZKWkR8mSNIZGuezEW OesFl4PO9fIYmvNu0whvz32VF7blMaP+3JjZwBU5f/MNOs5dKKcoykaLG/pDWiWi4pooQaa40s/ u9zOTsIPaejaw96pxz8FOovYGTPODzWUmAruZyM0ROXtuLn++RlboMvhVBU8LJMrEPlpEwyQeeU odZt1bAWe1ULcBc85i50ni28BeU+aDNoG+k7dBaNLiRTMlAvu64aONRTTp7lsjh2M7HJw== X-Google-Smtp-Source: AGHT+IF7WHk72PV+Zz1JrFgHqXqd6znxumWNzwk+VhqLWMQVBMpe1YBHsW3/jzrVYFRoEA7bWq5ZN2+DgAhyXqRsmGU= X-Received: by 2002:a05:6214:2a47:b0:882:4a63:63a7 with SMTP id 6a1803df08f44-8908430f1eemr44925386d6.60.1767810751218; Wed, 07 Jan 2026 10:32:31 -0800 (PST) Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 Date: Wed, 7 Jan 2026 21:32:20 +0300 X-Gm-Features: AQt7F2q7EeImQ8S_gG5tEaj2xMh8o1i1klRRqFyk06UlLQn860Lt8P5drlWTC5M Message-ID: Subject: [PHP-DEV] Improving PDO persistent connections and event loop support To: internals@lists.php.net Content-Type: multipart/alternative; boundary="000000000000db49180647d08375" From: go.al.ni@gmail.com --000000000000db49180647d08375 Content-Type: text/plain; charset="UTF-8" Hi. I would like to offer three changes to PDO module. 1. Cleanup persistent connection before passing it to next request Documentation on persistent connections [1] says: > Warning > PDO does not perform any cleanup of persistent connections. Temporary tables, locks, transactions and other stateful changes may remain from previous usage of the connection, causing unexpected problems. This makes persistent connections effectively unusable. I don't want to obtain dirty connection from previous request. In contrast, mysqli extension do automatic cleanup [2]: > The persistent connection of the mysqli extension however provides built-in cleanup handling code. Adding cleanup code to PDO will align persisting connection behavior with mysqli and make persistent connections safe to use. This is breaking change. 2. Add new method to PDO class - `reset()` This method will reset connection state. For mysql it will call C-API function `mysql_change_user()` like mysqli do. Most value this method would bring to event loop environments (more on this below), but also can be non breaking alternative to my first proposal - I just call this method on the very beginning of my script and proceed without fear, that everything may break due to garbage state from previous worker request. After calling proposed `refresh()` method: all still alive PDOStatement invalidated, logical db connection refreshed (e.g. mysql_change_user C-API called), underlying TCP/unix-socket/file-pointer connection stay intact. 3. Add new method to PDO class - `close()` PDO does not have method for closing connection. Documentation [1] says: > To close the connection, you need to destroy the object by ... assigning null to the variable that holds the object. Explicit close is not necessary for fpm and mod_php environments, because connection automatically closed at the end of script execution. But in event loops this may be complicated because of internal references to PDO object from PDOStatement objects [1]: > Note: If there are still other references to this PDO instance (such as from a PDOStatement instance, or from other variables referencing the same PDO instance), these have to be removed also (for instance, by assigning null to the variable that references the PDOStatement). After calling proposed `close()` method: all still alive PDOStatement objects invalidated, logical db connection closed (e.g. mysql_close C-API called), underlyind TCP/unix-socket/file-pointer connection closed. Event loop considerations Event loop based applications (e.g. roadrunner, frankenphp) are main intended users of `reset()` and `close()` methods. Event loop may look like: ```php // Example pseudocode $ev = setupEventLoopEnvironment(); $app = setupApplication(); while ($request = $ev->waitForRequest()) { $db = new PDO('dsn', 'user', 'password'); $app->setDb($db); $app->handle($request); $db = null; $app->setDb(null); } ``` Such approach may lead to db connection leak because application may unintentionally cache PDO or PDOStatement object that would prevent connection from closing. However, this may be handled by hiding PDO objects behind abstraction, provided by event loop framework. But performance impact cannot be avoided. More safe and performant variant using `reset()`: ```php $ev = setupEventLoopEnvironment(); $db = new PDO('dsn', 'user', 'password'); $app = setupApplication(); $app->setDb($db); while ($request = $ev->waitForRequest()) { $db->reset(); $app->handle($request); } ``` On this mail I focused on mysql. If the community is interested by the proposed changes, I'll investigate other supported db drivers as well and write RFC. [1] https://www.php.net/manual/en/pdo.connections.php [2] https://www.php.net/manual/en/mysqli.persistconns.php --000000000000db49180647d08375 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi. I would like to offer three changes to PDO module.
=
1. Cleanup persistent connection before passing it to next request
<= br>Documentation on persistent connections [1] says:

> Warning> PDO does not perform any cleanup of persistent connections. Temporary= tables, locks, transactions and other stateful changes may remain from pre= vious usage of the connection, causing unexpected problems.

This mak= es persistent connections effectively unusable. I don't want to obtain = dirty connection from previous request. In contrast, mysqli extension do au= tomatic cleanup [2]:

> The persistent connection of the mysqli ex= tension however provides built-in cleanup handling code.

Adding clea= nup code to PDO will align persisting connection behavior with mysqli and m= ake persistent connections safe to use. This is breaking change.

2. Add new method to PDO class - `reset()`

This method will reset c= onnection state. For mysql it will call C-API function `mysql_change_user()= ` like mysqli do. Most value this method would bring to event loop environm= ents (more on this below), but also can be non breaking alternative to my f= irst proposal - I just call this method on the very beginning of my script = and proceed without fear, that everything may break due to garbage state fr= om previous worker request.

After calling proposed `refresh()` metho= d: all still alive PDOStatement invalidated, logical db connection refreshe= d (e.g. mysql_change_user C-API called), underlying TCP/unix-socket/file-po= inter connection stay intact.


3. Add new method to PDO class - = `close()`

PDO does not have method for closing connection. Documenta= tion [1] says:

> To close the connection, you need to destroy the= object by ... assigning null to the variable that holds the object.
Explicit close is not necessary for fpm and mod_php environments, because = connection automatically closed at the end of script execution. But in even= t loops this may be complicated because of internal references to PDO objec= t from PDOStatement objects [1]:

> Note: If there are still other= references to this PDO instance (such as from a PDOStatement instance, or = from other variables referencing the same PDO instance), these have to be r= emoved also (for instance, by assigning null to the variable that reference= s the PDOStatement).

After calling proposed `close()` method: all st= ill alive PDOStatement objects invalidated, logical db connection closed (e= .g. mysql_close C-API called), underlyind TCP/unix-socket/file-pointer conn= ection closed.


Event loop considerations

Event loop based= applications (e.g. roadrunner, frankenphp) are main intended users of `res= et()` and `close()` methods. Event loop may look like:

```php
// = Example pseudocode
$ev =3D setupEventLoopEnvironment();
$app =3D setu= pApplication();

while ($request =3D $ev->waitForRequest()) {
= =C2=A0 $db =3D new PDO('dsn', 'user', 'password');<= br>=C2=A0 $app->setDb($db);
=C2=A0 $app->handle($request);
=C2= =A0 $db =3D null;
=C2=A0 $app->setDb(null);
}
```

Such a= pproach may lead to db connection leak because application may unintentiona= lly cache PDO or PDOStatement object that would prevent connection from clo= sing. However, this may be handled by hiding PDO objects behind abstraction= , provided by event loop framework. But performance impact cannot be avoide= d.

More safe and performant variant using `reset()`:

```php <= br>$ev =3D setupEventLoopEnvironment();
$db =3D new PDO('dsn', &= #39;user', 'password');
$app =3D setupApplication();
$app= ->setDb($db);

while ($request =3D $ev->waitForRequest()) {
= =C2=A0 $db->reset();
=C2=A0 $app->handle($request);
}
```
On this mail I focused on mysql. If the community is interested by the= proposed changes, I'll investigate other supported db drivers as well = and write RFC.


[1] https://www.php.net/manual/en/pdo.connections.php
[= 2] https:= //www.php.net/manual/en/mysqli.persistconns.php
--000000000000db49180647d08375--