Skip to content

Parameter binding

Greg Bowler edited this page Mar 3, 2026 · 3 revisions

Positional placeholders (?)

If you only need to bind one or two placeholders to your SQL, and their presence can be inferred by the name of the query, you can use positional placeholders by indicating where the variable data should be bound.

select id, name, email from user where id = ?

Then, to pass in the data, 42 in this case, you pass the data in as separate variadic function parameters.

$user = $db->fetch("user/getById", 42);

Because we only have a single placeholder in the getById query, the above code should be immediately obvious as to what it does, and what significance 42 has to the query (it's obviously the ID).

It would not be a good idea to use positional placeholders if there were many variables required, or the order could change in the query. When there are more placeholders required, named placeholders are recommended.

Named placeholders (:name)

Named placeholders allow you to name and reuse the placeholders, passing them into the query as an associative array. The placeholders are indicated by using a colon character followed by the placeholder name. The colon is not required to be present in the key of the associative array.

select id, name, email from user where email = :email and isActive = :isActive
$user = $db->fetch("user/getByEmail", [
	"email" => "dev@example.com",
	"isActive" => true,
]);

Value conversion rules

  • bool values automatically convert to 0 or 1, according to the database engine.
  • DateTimeInterface objects are automatically handled as strings in the format Y-m-d H:i:s.
  • arrays are expanded to indexed placeholders such as :ids__0, :ids__1, allowing for variable in( ... ) queries.

Special bindings

These values are injected into SQL after sanitisation:

  • :groupBy
  • :orderBy
  • :limit
  • :offset
  • :infileName

Example:

select 
	id, 
	email 
from 
	user

order by :orderBy
limit :limit 
offset :offset
$rows = $db->fetchAll("user/list", [
	"orderBy" => "id desc",
	"limit" => 20,
	"offset" => 40,
]);

Dynamic bindings

  • :__dynamicValueSet for generated multi-row insert value sets
  • :__dynamicIn for runtime IN (...) content
  • :__dynamicOr for grouped OR conditions

Dynamic bindings allow building flexible query templates without manual string concatenation in application logic.

Example code: example/04-dynamic-bindings.php


To learn more about working with result sets, move on to Type-safe getters.

Clone this wiki locally