@Dimon2x, ну типа того. Правда смысла в твоём коде 0. Вообще, очень тяжело привести короткий пример полиморфизма, поскольку он требуется обычно для достаточно сложных задач. Вот ты фреймворки ковыряешь, давай посмотрим на примере Yii2 и его Data Widgets и Data Provider. Data Widgets отображают данные, которые надо откуда-то сначала получить. Для того, чтобы получить данные используется Data Providers, ArrayDataProvider берёт данные из массивов (при этом, умеет пагинацию, умеет сортировку и т.п.), https://www.yiiframework.com/doc/api/2.0/yii-data-sqldataprovider - через прямой SQL запрос к базе, ActiveDataProvider - использует объекты запросов и ActiveRecord. При этом для Data Widgets всё равно, откуда DataProvider берёт данные, ему важно, чтоб он их ему отдавал. Вот это и полиморфизм. Я могу на этапе выполнения решить, какой ему передать DataProvider в зависимости от ситуации
класс который работает с объектами работающими с базой данных)) PHP: <?php /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ namespace natCMF\core; /** * Description of Db * * @author 27087 */ class Db { /** * Храним экземпляр текущего класса * @var object Db */ static private $_instance = null; /** * Храним объект работы с БД - имплементированный от интерфейса * DbInterface * @var object - implement DbInterface. На данный момент это может быть * DbMysqli или DbSqlite3 */ private $_db = null; /** * Создаем подключенте БД * @return object Db - возвращает экземпляр себя хранимый в _instance */ static public function getInstance() { if (is_null(self::$_instance)) { self::$_instance = new self; //Достали параметры подключения к БД $dbParams = Config::get('dbParams'); //Возможные БД $possibleDb = Config::get('possibleDb'); //Создаем объект $dbDriver = $possibleDb[$dbParams['dbType']]; self::$_instance->_db = new $dbDriver($dbParams); } return self::$_instance; } /** * Запрос к БД * @param string $query * @param array $values * @return object */ static function query($query, $values = []) { return self::getInstance()->_db->query($query, $values); } /** * Возвращает количество строк полученых в результате запроса к БД * @param type $result * @return int */ static function numRows($result) { return self::getInstance()->_db->numRows($result); } static function lastInsertId($result) { return self::getInstance()->_db->lastInsertId($result); } /** * Очищает объект БД * @param type $result * @return boolean */ static function freeResult(&$result) { return self::getInstance()->_db->freeResult($result); } /** * Перебирая объект $result возвращает строки в виде ассоциативного * массива * @param type $result * @return array */ static function fetchAssoc($result) { return self::getInstance()->_db->fetchAssoc($result); } /** * Перебирая объект $result возвращает строки в виде индексированного * массива * @param type $result * @return array */ static function fetchRow($result) { return self::getInstance()->_db->fetchRow($result); } /** * Получаем информацию о модели/таблице * @param type $table * @return array */ static function tableInfo($table) { return self::getInstance()->_db->tableInfo($table); } /** * Возвращает количество запросов сделанных к базе * @return int */ static function getCountQuery() { return self::getInstance()->_db->getCountQuery(); } } --- Добавлено --- интерфейс PHP: <?php /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ namespace natCMF\core\sql; /** * Description of DbInterface * * @author 27087 */ interface DbInterface { public function __construct($dbParams); public function query( $query, $values = []); public function numRows($result); public function freeResult(&$result); public function fetchAssoc($result); public function fetchRow($result); public function tableInfo($table); public function getCountQuery(); } --- Добавлено --- Класс для работы с mysqli Код (Text): namespace natCMF\core\sql; use natCMF\core\sql\DbInterface; /** * Description of DbMysqli * * @author 27087 */ class DbMysqli implements DbInterface { private $db = null; private $dbPrefix = null; private $colTypeLink = [ 'varchar' => 'string', 'text' => 'string', 'int' => 'int', 'float' => 'float', ]; private $_count = 0; public function __construct($dbParams) { $this->dbPrefix = $dbParams['dbPrefix']; $db = new \mysqli($dbParams['dbHost'], $dbParams['dbUser'], $dbParams['dbPass'], $dbParams['dbName']); $db->set_charset('utf8mb4'); $db->character_set_name(); $db->query("SET CHARACTER SET utf8mb4"); if (empty($db->errno)) { $this->db = $db; } } /** * * @param string $query - запрос * с плейсхолдерами int|float|string|array_int|array_string * id={int:id} AND id_member IN(array_ind:ids) * @param array $values массив с даными для плейсходеров * [ id=>1, ids=>[1,2,3,4,5] ] * @return object mysqli_result */ public function query(string $query, array $values = []) { //Считаем запросы к БД $this->_count++; /* Типы плейсхолдеров */ $pattern = '~{(int|float|string|array_int|array_string):(\S+?)}~'; /* Выбираем из строки запрос возможные плейсходеры */ $matches = []; preg_match_all($pattern, $query, $matches, PREG_SET_ORDER); /* Инициализируем массив с данными плейсхолтера */ $prepareData = []; /* и массив с типами плейсхолдера mysqli * i - соответствующая переменная имеет тип integer * d - соответствующая переменная имеет тип double * s - соответствующая переменная имеет тип string * b - соответствующая переменная является большим двоичным объектом (blob) и будет пересылаться пакетами */ $typesPlaceholders = ''; /* Обходим найденные плейсхолдеры */ foreach ($matches as $ph) { /* Временный плейсхоллер нужен для типов плейсхолдеров array_XXX знак вопроса ? для самого запроса */ $tmpPlaceholers = ''; switch ($ph['1']) { case 'int': $typesPlaceholders .= 'i'; $prepareData[] = (int) $values[$ph['2']]; $tmpPlaceholers = '?'; break; case 'array_int': $tmpPlaceholers = ''; foreach ($values[$ph['2']] as $intVal) { $typesPlaceholders .= 'i'; $prepareData[] = (int) $intVal; $tmpPlaceholers .= '?,'; } $tmpPlaceholers = trim($tmpPlaceholers, ','); break; case 'string': $typesPlaceholders .= 's'; $prepareData[] = (string) $values[$ph['2']]; $tmpPlaceholers = '?'; break; case 'array_string': break; default: die('Неверный тип даннных ' . $ph['1']); break; } /* Заменили плейсхолдер на нужное количество знаков вопросов */ $query = str_replace($ph['0'], $tmpPlaceholers, $query); } /* Заменили плейсхолдер префикса таблицы на сам префикс */ $query = str_replace('{db_prefix}', $this->dbPrefix, $query); /* Собрали массив для вызова метода */ $params['db_types'] = $typesPlaceholders; foreach ($prepareData as $key => $val) { $params['db_' . $key] = &$prepareData[$key]; } /* Готовим запрос и выполняем */ $stmt = $this->db->stmt_init(); $stmt->prepare($query); if ($stmt->error) { var_dump($query); var_dump($stmt->error); } if (!empty($params['db_types'])) { call_user_func_array([$stmt, 'bind_param'], $params); } $stmt->execute(); //Если INSERT то возвращаем то что показал stmp if (!empty($stmt->insert_id)) { $result = new \stdClass(); foreach ($stmt as $key => $value) { $result->$key = $stmt->$key; } } //Если запрос был SELECT, UPDATE, DELETE - тогда берем результат else { $result = $stmt->get_result(); } $stmt->close(); return $result; } /** * Количество записей в результате запроса * @param object \mysqli_result $result * @return int */ public function numRows($result) { return $result->num_rows; } /** * Очищаем mysqli_result * @param $result - object \mysqli_result * @return boolean */ public function freeResult(&$result) { return $result->free_result(); } /** * Получаем ассоциативный массив с mysqli_result и передвигаем указатель на * следующий элемент * @param $result - object \mysqli_result * @return array - массив с результаом */ public function fetchAssoc($result) { return $result->fetch_assoc(); } /** * * @param $result - object \mysqli_result * @return type */ public function fetchRow($result) { return $result->fetch_row(); } /** * * @param type $table * @return type */ public function tableInfo($table) { return $this->tableInfoAdaptation($rows); } /** * * @param type $result * @return type */ private function tableInfoAdaptation($result) { return $linksType; } /** * Возвращаем количество запросов к БД * @return int */ public function getCountQuery() { return $this->_count; } }
нет, неа, найн.... бинд парам в калле не правильно. А если мы произведем insert с множественными вставками строк ? --- Добавлено --- PHP: <?php error_reporting ( E_ALL ); $m = new mysqli( 'localhost', 'root', '', 'git', 3306 ); $stmt = $m -> prepare( 'SELECT * FROM lerma WHERE id IN( ?, ? )'); $executes = [138,139];#, [141,142] ]; /* ... */ $executes = ( is_array ( $executes[0] ) ? $executes : [ $executes ] ); $count = count ( $executes[0] ); $for = (array)implode ( '', array_map ( function ( $arg ) { if ( !in_array ( $type = gettype ( $arg ), [ 'integer', 'double', 'string' ] ) ) { throw new Error( 'Invalid type ' . $type ); } return $type[0]; }, $executes[0] ) ); for ( $i = 0; $i < $count; $i++ ) { $for[] = &${ 'bind_' . $i }; } $ReflectionMethod = new ReflectionMethod( 'mysqli_stmt', 'bind_param' ); $ReflectionMethod -> invokeArgs( $stmt, $for ); foreach ( $executes AS $items ) { #$items = executeHolders( $items ); extract ( $items, EXTR_PREFIX_ALL, 'bind' ); $stmt -> execute(); } /* ... */ $get = $stmt -> get_result(); print_r ( $get -> fetch_all( MYSQLI_ASSOC ) ); --- Добавлено --- На счет плейсхолдеров, научил PHP: SELECT * FROM lerma WHERE id = :id PHP: <?php namespace Aero\Low\Lerma; trait Placeholders { protected $pattern = '/(\?|:[a-z]{1,})/'; # Поиск плейсхолдеров в запросе protected $matches; # Placeholders /* - Поиск ':', замена placeholders на '?' */ public function replaceHolders( $sql ): string { $this -> matches = []; $sql = ( is_array ( $sql ) ? sprintf ( ...$sql ) : $sql ); if ( strpos ( $sql, ':' ) !== false ) { preg_match_all ( $this -> pattern, $sql, $matches ); $this -> matches = $matches[1]; $sql = strtr ( $sql, array_fill_keys ( $this -> matches, '?' ) ); } return $sql; } /* - Реформирование данных в массиве по найденным placeholders */ public function executeHolders( array $execute ): array { $new = []; foreach ( $this -> matches as $plaseholder ) { if ( $plaseholder === '?' ) { $new[] = array_shift ( $execute ); } else { if ( isset ( $new[$plaseholder] ) ) { $new[] = $new[$plaseholder]; } else { $new[$plaseholder] = $execute[$plaseholder] ?? null; unset ( $execute[$plaseholder] ); } } } return $new ?? $execute; } } --- Добавлено --- перед query / prepare юзается метод replaceHolders executeHolders в первом коде за комментирован
@Dimon2x, ты вообще рекомендованную литературу читаешь? https://www.ozon.ru/context/detail/id/33506422/ - раскопай вот эту книгу, разбери. Читай доки к используемым фреймворкам (а то по коду, что ты выкладываешь, часто видно, что не читал).
Большая часть не претерпит изменений, так что можешь читать любое. Потом просто посмотреть в мануале php, что в нём появилось нового. Если поймёшь книжку, разберёшься и с этим.