Соберите fluent-сборщик запросов с цепочкой вызовов
Реализуйте fluent-сборщик запросов по одной таблице. select(), where() и orderBy() должны выстраиваться в цепочку в любом порядке, а toSql() — возвращать собранную строку SQL.
Требования: каждый метод цепочки возвращает сам сборщик, чтобы вызовы связывались; where() можно вызвать несколько раз, и условия объединяются через AND; toSql() возвращает строку и не меняет состояние сборщика.
<?php
class QueryBuilder {
private array $columns = [];
private array $wheres = [];
private ?string $order = null;
public function __construct(private string $table) {}
public function select(string ...$columns): static {
// ваш код здесь
}
public function where(string $condition): static {
// ваш код здесь
}
public function orderBy(string $column): static {
// ваш код здесь
}
public function toSql(): string {
// ваш код здесь
}
}
Допишите реализацию.
Каждый метод цепочки меняет состояние сборщика и возвращает $this с типом static, чтобы наследник тоже продолжал цепочку, — именно это позволяет связывать вызовы. toSql() — терминальный метод: он возвращает собранную строку, а не сборщик, и цепочка на нём заканчивается.
- ✗Забыть
return $this, из-за чего следующий вызов цепочки приходит наnull - ✗Указать тип возврата
selfвместоstatic, что ломает цепочку в наследнике - ✗Заставить терминальный
toSql()вернуть сборщик вместо собранной строки
- →Почему тип возврата
staticсохраняет цепочку в наследнике там, гдеselfеё ломает? - →Как сделать сборщик неизменяемым, чтобы каждый вызов возвращал изменённую копию?
Цепочка держится на одном правиле: каждый метод, который должен продолжать цепочку, меняет состояние и возвращает $this. Тип возврата — static, а не self, чтобы наследник получил свой тип и цепочка не «схлопнулась» к родителю.
<?php
class QueryBuilder {
private array $columns = [];
private array $wheres = [];
private ?string $order = null;
public function __construct(private string $table) {}
public function select(string ...$columns): static {
$this->columns = array_merge($this->columns, $columns);
return $this;
}
public function where(string $condition): static {
$this->wheres[] = $condition;
return $this;
}
public function orderBy(string $column): static {
$this->order = $column;
return $this;
}
public function toSql(): string {
$cols = $this->columns ? implode(', ', $this->columns) : '*';
$sql = "SELECT {$cols} FROM {$this->table}";
if ($this->wheres) {
$sql .= ' WHERE ' . implode(' AND ', $this->wheres);
}
if ($this->order !== null) {
$sql .= " ORDER BY {$this->order}";
}
return $sql;
}
}
toSql() — терминальный метод: он возвращает строку, а не сборщик, поэтому цепочку продолжить нельзя, и это правильно. Условия where() накапливаются в массиве и склеиваются через AND, поэтому порядок вызовов не важен.