Это класс БД: PHP: class DB { protected $dbname; protected $user; protected $password; protected $host; protected $port; protected $charset; protected $connection; protected $statement; protected $queries = []; public function __construct($dbname, $user = 'root', $password = '', $host = 'localhost', $port = 3306, $charset = 'utf8') { $this->dbname = $dbname; $this->user = $user; $this->password = $password; $this->host = $host; $this->port = $port; $this->charset = $charset; } public function connect() { if ($this->connection) { return; } $dsn = sprintf( 'mysql:dbname=%s;host=%s;port=%d;charset=%s', $this->dbname, $this->host, $this->port, $this->charset ); try { $this->connection = new PDO($dsn, $this->user, $this->password, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ]); } catch (PDOException $e) { throw new RuntimeException($e->getMessage()); } } public function disconnect() { $this->connection = null; } public function query($sql, $bind = []) { // Подключаемся при первом запросе $this->connect(); try { $t = -microtime(1); $this->statement = $this->connection->prepare($sql); $this->statement->execute($bind); $t += microtime(1); $this->queries[$sql] = $t; return $this; } catch (PDOException $e) { throw new RuntimeException($e->getMessage()); } } function select($table, $conditions = [], $sort = [], $limit = 0, $offset = 0) { $bind = array_values($conditions); $where = []; foreach (array_keys($conditions) as $column) { $where[] = $this->quoteIdentifier($column) . ' = ?'; } $order_by = []; foreach ($sort as $column => $order) { $order = trim($order); $order = $order === 'ASC' ?: 'DESC'; $order_by[] = sprintf('%s %s', $this->quoteIdentifier($column), $order); } $sql = sprintf( 'SELECT * FROM %s%s%s%s;', $this->quoteIdentifier($table), $where ? ' WHERE ' . implode(' AND ', $where) : '', $order_by ? ' ORDER BY ' . implode(', ', $order_by) : '', $limit ? sprintf(' LIMIT %d, %d', $offset, $limit) : '' ); $this->query($sql, $bind); return $this; } public function insert($table, $data) { $sql = sprintf( 'INSERT INTO %s (%s) VALUES (%s);', $this->quoteIdentifier($table), implode(', ', array_map([$this, 'quoteIdentifier'], array_keys($data))), substr(str_repeat('?, ', count($data)), 0, -2) ); $this->query($sql, array_values($data)); return $this->lastInsertId(); } public function update($table, $data, $conditions) { $bind = array_values($data); $set = []; foreach (array_keys($data) as $column) { $set[] = $this->quoteIdentifier($column) . ' = ?'; } $where = []; foreach ($conditions as $column => $value) { $where[] = $this->quoteIdentifier($column) . ' = ?'; $bind[] = $value; } $sql = sprintf( 'UPDATE %s SET %s WHERE %s;', $this->quoteIdentifier($table), implode(', ', $set), implode(' AND ', $where) ); return $this->query($sql, $bind)->affectedRows(); } public function delete($table, $conditions) { $bind = array_values($conditions); $where = []; foreach (array_keys($conditions) as $column) { $where[] = $this->quoteIdentifier($column) . ' = ?'; } $sql = sprintf( 'DELETE FROM %s WHERE %s;', $this->quoteIdentifier($table), implode(' AND ', $where) ); return $this->query($sql, $bind)->affectedRows(); } public function fetch() { try { return $this->statement->fetch(); } catch (PDOException $e) { throw new RuntimeException($e->getMessage()); } } public function fetchOne() { try { return $this->statement->fetchColumn(); } catch (PDOException $e) { throw new RuntimeException($e->getMessage()); } } public function fetchAll() { try { return $this->statement->fetchAll(); } catch (PDOException $e) { throw new RuntimeException($e->getMessage()); } } public function affectedRows() { try { return $this->statement->rowCount(); } catch (PDOException $e) { throw new RuntimeException($e->getMessage()); } } public function lastInsertId() { try { return $this->connection->lastInsertId(); } catch (PDOException $e) { throw new RuntimeException($e->getMessage()); } } public function beginTransaction() { try { return $this->connection->beginTransaction(); } catch (PDOException $e) { throw new RuntimeException($e->getMessage()); } } public function commit() { try { return $this->connection->commit(); } catch (PDOException $e) { throw new RuntimeException($e->getMessage()); } } public function rollBack() { try { return $this->connection->rollBack(); } catch (PDOException $e) { throw new RuntimeException($e->getMessage()); } } public function quoteIdentifier($name) { return '`' . str_replace('`', '``', $name) . '`'; } public function getQueries() { return $this->queries; } public function __destruct() { $this->disconnect(); }} В нем много копипасты. Это уже реализация: PHP: abstract class Entity implements IteratorAggregate { protected $data; public function __construct(array $data = []) { $this->data = $data; } public function __set($property, $value) { $this->data[$property] = $value; } public function __get($property) { return $this->data[$property] ?? null; } public function __isset($property) { return isset($this->data[$property]); } public function __unset($property) { unset($this->data[$property]); } public function getIterator() { $obj = new ArrayObject($this->data); return $obj->getIterator(); } public function toArray() { return $this->data; }}// Код ужасенabstract class EntityMapper { protected $db; protected $fields = []; protected $primaryKey; // Эти свойства переопределяются в классах наследниках protected $table; protected $entitylClass; public function __construct($db) { $this->db = $db; $this->describeFields(); } public function find($id) { $row = $this->db->select($this->table, [$this->primaryKey => $id])->fetch(); return $row ? $this->createEntity($row) : null; } public function findAll(array $conditions = [], array $sort = [], int $limit = 0, int $offset = 0): array { $rows = $this->db->select($this->table, $conditions, $sort, $limit, $offset)->fetchAll(); return $this->createEntities($rows); } public function save(Entity $entry): bool { $data = []; foreach ($this->fields as $field) { $data[$field] = $entry->$field; } if ($entry->{$this->primaryKey}) { unset($data[$this->primaryKey]); return (bool) $this->db->update($this->table, $data, [ $this->primaryKey => $entry->{$this->primaryKey} ]); } $id = $this->db->insert($this->table, $data); if ($id) { $entry->{$this->primaryKey} = $id; return true; } return false; } public function delete(Entity $entry): bool { $affected = $this->db->delete($this->table, [ $this->primaryKey => $entry->{$this->primaryKey} ]); if ($affected) { $entry->{$this->primaryKey} = null; return true; } return false; } protected function describeFields() { $sql = sprintf('DESCRIBE %s;', $this->db->quoteIdentifier($this->table)); $rows = $this->db->query($sql)->fetchAll(); foreach ($rows as $row) { $this->fields[] = $row['Field']; if ($row['Key'] === 'PRI') { $this->primaryKey = $row['Field']; } } } protected function createEntity(array $row) { return new $this->entityClass($row); } protected function createEntities(array $rows) { return array_map([$this, 'createEntity'], $rows); }}class MapperRepository { protected $db; protected $mappers = []; public function __construct(DB $db) { $this->db = $db; } public function getDB() { return $this->db; } public function getMapper($name) { if (!isset($this->mappers[$name])) { $this->mappers[$name] = new $name($this->db); } return $this->mappers[$name]; }} Тест: PHP: class User extends Entity { // Add some methods}class UserMapper extends EntityMapper { protected $table = 'users'; protected $entityClass = 'User';}/*CREATE TABLE `users` (`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(20) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,`email` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,`password` varchar(20) NOT NULL,PRIMARY KEY (`id`),UNIQUE KEY `username` (`username`),UNIQUE KEY `email` (`email`)) ENGINE=InnoDB DEFAULT CHARSET=utf8*/function dump($v) { echo '<pre>' . print_r($v, 1) . '</pre>';}$db = new DB('test');$repo = new MapperRepository($db);$user = new User([ 'username' => 'u' . uniqid(), 'email' => uniqid() . '@example.com', 'password' => substr(md5(uniqid()), 0, 6)]);$map = $repo->getMapper('UserMapper');$map->save($user);$users = $map->findAll([], ['id' => null], 10);dump($users);dump($db->getQueries()); Вывод: Code: Array ( [0] => User Object ( [data:protected] => Array ( [id] => 35 [username] => u595bbe5e129fd [email] => [email protected] [password] => 1ecfee ) ) [1] => User Object ( [data:protected] => Array ( [id] => 34 [username] => u595bbe5dd20eb [email] => [email protected] [password] => 134a6a ) ) [2] => User Object ( [data:protected] => Array ( [id] => 33 [username] => u595bbe5d777d6 [email] => [email protected] [password] => 01ffec ) ) [3] => User Object ( [data:protected] => Array ( [id] => 32 [username] => u595bbe5d130ac [email] => [email protected] [password] => 2a64bc ) ) [4] => User Object ( [data:protected] => Array ( [id] => 31 [username] => u595bbe5cd9b8d [email] => [email protected] [password] => 3ef9e6 ) ) [5] => User Object ( [data:protected] => Array ( [id] => 30 [username] => u595bbe5c84d33 [email] => [email protected] [password] => 1f0196 ) ) [6] => User Object ( [data:protected] => Array ( [id] => 29 [username] => u595bbe5c56495 [email] => [email protected] [password] => 6624e1 ) ) [7] => User Object ( [data:protected] => Array ( [id] => 28 [username] => u595bbe5c0bafb [email] => [email protected] [password] => c08747 ) ) [8] => User Object ( [data:protected] => Array ( [id] => 27 [username] => u595bbe5b98df5 [email] => [email protected] [password] => f171dd ) ) [9] => User Object ( [data:protected] => Array ( [id] => 26 [username] => u595bbe4dde2a1 [email] => [email protected] [password] => 8305f7 ) ) ) Array ( [DESCRIBE `users`;] => 0.0033631324768066 [INSERT INTO `users` (`id`, `username`, `email`, `password`) VALUES (?, ?, ?, ?);] => 0.048413991928101 [SELECT * FROM `users` ORDER BY `id` DESC LIMIT 0, 10;] => 0.00035905838012695 ) Скажите где у меня ошибки в реализации? код на 100% рабочий.