Пример ООП с PHP и MySql
Если вы найдете критические помарки по переводу, пожалуйста, оставляйте комментарии. Ваши замечания обязательно будут учтены. В любом случае надеюсь, вы найдете данную статью весьма полезной.
Существует множество различных, простых примеров, в которых приводится принцип работы ООП. Сегодня я решил показать вам, как работает ООП (Объектно-ориентированное, или объектное, программирование) в реальной жизни; особенно данный пример пригодится начинающим программистам. Создав класс под MYSQL CRUD (CRUD —англ. create read update delete — «Создание чтение обновление удаление»), вы сможете легко создавать, читать, обновлять и удалять записи в любых ваших проектах, независимо от того, как спроектирована база данных.
Как только вы поймете, что нам требуется, вы легко создадите скелет для нашего класса. Для начала нам надо включить в класс основные функции для работы с MySQL. Потребуются следующие функции.
- Select
- Insert
- Delete
- Update
- Connect
- Disconnect
Ниже приведено определение нашего класса. Отметьте, что все методы, которые я создал, используют ключевое слово
public
.
PHP
class Database
{
public function connect() { }
public function disconnect() { }
public function select() { }
public function insert() { }
public function delete() { }
public function update() { }
}
Функция
connect()
Эта функция будет довольно простой, но прежде чем писать функцию, нам потребуется определить несколько переменных. Переменные должны быть доступны только в пределах класса, поэтому перед каждой переменной стоит ключевое слово
private
(закрытый). Все переменные (хост, имя пользователя, пароль, имя база данных) используются для соединения с базой данных MySQL. После этого мы сможем создать простой MySQL запрос к базе данных. Конечно, как программисты, мы должны ожидать от пользователей все что угодно, и исходя из этого, нам необходимо принять определенные меры предосторожности. Мы можем проверить: если пользователь уже подключен к базе данных, то , соответственно, ему не нужно повторно подключаться к БД. В противном случае, мы можем использовать учетные данные пользователя для подключения.
PHP
private db_host = ‘’;
private db_user = ‘’;
private db_pass = ‘’;
private db_name = ‘’;
/*
* Соединяемся с бд, разрешено только одно соединение
*/
public function connect()
{
if(!$this->con)
{
$myconn = @mysql_connect($this->db_host,$this->db_user,$this->db_pass);
if($myconn)
{
$seldb = @mysql_select_db($this->db_name,$myconn);
if($seldb)
{
$this->con = true;
return true;
} else
{
return false;
}
} else
{
return false;
}
} else
{
return true;
}
}
Как видите выше, мы используем базовые функции MySQL и делаем небольшую проверку на ошибки, чтобы все шло по плану. Если пользователь подключился к БД, мы возвращаем
true
, в ином случае возвращаем false. В качестве дополнительного бонуса устанавливаем переменную (
con
) в true, если соединение установлено.
Общедоступная (
public
) функция
disconnect()
Функция проверяет переменную соединения на существование. Если соединение установлено (
con
есть), то закрываем соединение с БД MySQL и возвращаем
true
. Иначе делать ничего не нужно.
PHP
public function disconnect()
{
if($this->con)
{
if(@mysql_close())
{
$this->con = false;
return true;
}
else
{
return false;
}
}
}
Общедоступная (public) функция select()
Переходим к той части, где все немного усложняется. Мы начинаем работать с аргументами пользователя и возвращаем результаты запроса. У нас нет необходимости использовать результаты прямо сейчас, но нам необходимо создать переменную, в которой мы будем хранить пользовательские результаты по запросам из БД. Кроме того мы также создадим новую функцию, которая будет проверять существует ли данная таблица в БД. Эта функция будет создана отдельно, так как все наши CRUD операции потребуют такой проверки. Таким образом, это немного очистит наш код и в дальнейшем будет способствовать оптимизации кода. Ниже приведена функция для проверки таблиц (
tableExists
) и общедоступная переменная с результатами запросов.
PHP
private $result = array();
/*
* Проверяем наличие таблицы при выполнении запроса
*
*/
private function tableExists($table)
{
$tablesInDb = @mysql_query('SHOW TABLES FROM '.$this->db_name.' LIKE "'.$table.'"');
if($tablesInDb)
{
if(mysql_num_rows($tablesInDb)==1)
{
return true;
}
else
{
return false;
}
}
}
Эта функция просто проверяет наличие нужной таблицы в БД. Если таблица существует, вернет
true
, иначе вернет
false
.
PHP
/*
* Выборка информации из бд
* Требуется: table (наименование таблицы)
* Опционально: rows (требуемые колонки, разделитель запятая)
* where (колонка = значение, передаем строкой)
* order (сортировка, передаем строкой)
*/
public function select($table, $rows = '*', $where = null, $order = null)
{
$q = 'SELECT '.$rows.' FROM '.$table;
if($where != null)
$q .= ' WHERE '.$where;
if($order != null)
$q .= ' ORDER BY '.$order;
if($this->tableExists($table))
{
$query = @mysql_query($q);
if($query)
{
$this->numResults = mysql_num_rows($query);
for($i = 0; $i < $this->numResults; $i++)
{
$r = mysql_fetch_array($query);
$key = array_keys($r);
for($x = 0; $x < count($key); $x++)
{
// Sanitizes keys so only alphavalues are allowed
if(!is_int($key[$x]))
{
if(mysql_num_rows($query) > 1)
$this->result[$i][$key[$x]] = $r[$key[$x]];
else if(mysql_num_rows($query) < 1)
$this->result = null;
else
$this->result[$key[$x]] = $r[$key[$x]];
}
}
}
return true;
}
else
{
return false;
}
}
else
return false;
}
На первый взгляд выглядит устрашающе, но при этом здесь мы делаем целую кучу важных вещей. Функция принимает четыре аргумента, один из которых обязательный.
Функция вернет результат при наличии единственного аргумента - имени таблицы. Однако вы можете расширить количество аргументов и добавить новые аргументы, которые вы сможете использовать при работе с БД; ведь корректное исполнение функции зависит от одного аргумента – имени таблицы. Код в пределах функции служит для компиляции всех аргументов в select запрос. Как только запрос будет составлен, понадобится проверка на наличие в БД нужной таблицы – для этого используется функция
tableExists
. Если таблица найдена, то функция будет продолжена и запрос будет отправлен. Иначе все застопорится.
В следующей секции приведен действительно магический код. Суть в следующем: собрать данные запрошенные из таблицы. Затем присваиваем наш результат переменной. Чтобы упростить результат для конечного пользователя вместо числовых ключей будем использовать имена столбцов. В случае если количество строк таблицы больше единицы, на выходе вы получите двумерный массив, в котором первый ключ - это число (инкремент), второй ключ - это название колонки. Если в таблице всего одна строка, будет возвращен одномерный массив, название ключей которого соответствует именам столбцов таблицы. Если строк в таблице не найдено, переменной
result
будет присвоено значение
null
. Как я сказал ранее, все выглядит немного запутанным, но стоит вам разбить код на отдельные секции все станет гораздо проще и понятнее.
Общедоступная (
public
) функция
insert()
Эта функция немного проще, чем предыдущие. Она просто позволяет вставить информацию в БД. Таким образом, помимо имени таблицы нам потребуются дополнительные аргументы. Нам потребуется переменная, которая будет содержать соответствующие для вставки в таблицу значения. Затем мы просто отделим каждое значение запятой. Также мы проверяем при помощи функции
tableExists
наличие нужной таблицы и составляем insert запрос, манипулируя аргументами, переданными в функцию
insert()
. Затем отправляем наш запрос по нужному адресу.
PHP
/*
* Вставляем значения в таблицу
* Требуемые: table (наименование таблицы)
* values (вставляемые значения, передается массив значений, например,
* array(3,"Name 4","this@wasinsert.ed"); )
* Опционально:
* rows (название столбцов, куда вставляем значения, передается строкой,
* например, 'title,meta,date'
*
*/
public function insert($table,$values,$rows = null)
{
if($this->tableExists($table))
{
$insert = 'INSERT INTO '.$table;
if($rows != null)
{
$insert .= ' ('.$rows.')';
}
for($i = 0; $i < count($values); $i++)
{
if(is_string($values[$i]))
$values[$i] = '"'.$values[$i].'"';
}
$values = implode(',',$values);
$insert .= ' VALUES ('.$values.')';
$ins = @mysql_query($insert);
if($ins)
{
return true;
}
else
{
return false;
}
}
}
Как видите эта функция довольно простая, по сравнению с составлением запросов select к БД. На самом деле функция delete будет еще проще.
Общедоступная (
public
) функция
delete()
Эта функция просто удаляет таблицу или строки из нашей БД. Таким образом, нам надо передать в функцию имя таблицы и опциональный аргумент определяющий условие
where
. В условии следующим за ключевым словом
WHERE
следует уточнение: удалить строку, строки или всю таблицу. Если условие where опущено, то будут удалены все строки. Затем составляется запрос
delete
и следует выполнение запроса.
PHP
/*
* Удаяем таблицу или записи удовлетворяющие условию
* Требуемые: таблица (наименование таблицы)
* Опционально: где (условие [column = value]), передаем строкой, например, 'id=4'
*/
public function delete($table,$where = null)
{
if($this->tableExists($table))
{
if($where == null)
{
$delete = 'DELETE '.$table;
}
else
{
$delete = 'DELETE FROM '.$table.' WHERE '.$where;
}
$del = @mysql_query($delete);
if($del)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
Наконец перейдем к нашей последней основной функции. Эта функция служит для обновления строки в БД новой информацией. Данная функция на первый взгляд сложна для понимания, однако, это не совсем так. Мы будем использовать все те же принципы, что и раньше. Например, аргументы будут использоваться для составления запроса
update
. Также мы проверим наличие таблицы при помощи метода
tableExists
. Если таблица существует, обновим надлежащую строку. Самая сложная часть, конечно, та, где мы занимаемся составлением запроса
update
. Поскольку оператор
update
имеет правило за раз обновлять все строки, нам необходимо учесть это и правильно отрегулировать этот момент. Итак, я решил условие
where
передавать как простой массив. Первый аргумент в этом массиве - имя столбца, следующий аргумент значений столбца. Таким образом, каждый четный номер (включай 0) соответствует имени колонки, а каждый нечетный номер содержит нечетное значение. Соответствующий код приведен ниже:
PHP
for($i = 0; $i < count($where); $i++)
{
if($i%2 != 0)
{
if(is_string($where[$i]))
{
if(($i+1) != null)
$where[$i] = '"'.$where[$i].'" AND ';
else
$where[$i] = '"'.$where[$i].'"';
}
}
}
$where = implode($condition,$where);
В следующей секции мы создадим часть
update
оператора, настраивая переменные. Поскольку вы можете изменить любое числовое значение, я предпочел массив с ключами по названию столбца и новыми значениями. Таким образом, нам останется сделать проверку на тип значения и где нужно поставить запятую.
Теперь, когда мы составили две основных части оператора
update
, завершить составление оператора
update
не составит труда, код представлен ниже:
PHP
public function update($table,$rows,$where,$condition)
{
if($this->tableExists($table))
{
// Parse the where values
// even values (including 0) contain the where rows
// odd values contain the clauses for the row
for($i = 0; $i < count($where); $i++)
{
if($i%2 != 0)
{
if(is_string($where[$i]))
{
if(($i+1) != null)
$where[$i] = '"'.$where[$i].'" AND ';
else
$where[$i] = '"'.$where[$i].'"';
}
}
}
$where = implode($condition,$where);
$update = 'UPDATE '.$table.' SET ';
$keys = array_keys($rows);
for($i = 0; $i < count($rows); $i++)
{
if(is_string($rows[$keys[$i]]))
{
$update .= $keys[$i].'="'.$rows[$keys[$i]].'"';
}
else
{
$update .= $keys[$i].'='.$rows[$keys[$i]];
}
// Parse to add commas
if($i != count($rows)-1)
{
$update .= ',';
}
}
$update .= ' WHERE '.$where;
$query = @mysql_query($update);
if($query)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
Итак, мы закончили создание последней функции и наш класс для работы с CRUD можно считать законченным. Теперь вы можете создавать новые записи, читать отдельные записи из БД, обновлять записи и удалять. Кроме того, начав повторно использовать данный класс, вы обнаружите, что существенно экономите время и строчки код. То есть вы почувствуете эффективность и преимущество ООП.
Использование
Итак, мы создали наш класс, но как его использовать? Тут все просто. Давайте начнем с создания простой БД, в которой протестируем наш класс. Я создал базу данных
test
и составил простой mysql оператор. Вы можете поместить его в любую БД.
Первая строка закомментирована, так как она не всегда необходима. Если вам необходимо запустить предыдущий код более одного раза, вам потребуется раскомментировать первую строку, чтобы быть уверенным, что таблица создана.
Теперь, когда наша таблица создана и заполнена, самое время запустить несколько простых запросов.
PHP
<?php
include('crud.php');
$db = new Database();
$db->connect();
$db->select('mysqlcrud');
$res = $db->getResult();
print_r($res);
?>
Если все сделано корректно, вы увидите следующие:
Аналогичным образом мы можем запустить запрос на обновление и вывести результаты.
PHP
<?php;
$db->update('mysqlcrud',array('name'=>'Changed!'),array('id',1),"=");
$db->update('mysqlcrud',array('name'=>'Changed2!'),array('id',2),"=");
$res = $db->getResult();
print_r($res);
?>
На выходе:
Теперь просто вставим запись:
PHP
<?php;
$db->insert('mysqlcrud',array(3,"Name 4","this@wasinsert.ed"));
$res = $db->getResult();
print_r($res);
?>
Источник
Комментарии к статье
В методе delete() в случае очистки всей таблицы неверен запрос. Правильно будет "DELETE FROM $table"
в запросах на удаление и обновление нужно жестко указывать лимит, LIMIT 1
в запросах на удаление и обновление нужно жестко указывать лимит, LIMIT 1
ходу добавить на всё нужно добавить парамер LIMIT и применять например выбрать из таблы лимит 30 полей или выбрать из таблы с 30 по 90 и тд.
P.S идея хорошая но сыроватая .требует дороботок.для новичка это как урок но не для использования :)
конечно, требуется подумать немного доработать и использовать, как и все и везде
Интересный класс. Но я нигде не увидел описание метода getResult() которым вы успешно пользуетесь.... если можете добавьте. Я начинающий ООП программист и мне интересно как он реализовывается . Заранее спасибо
private $result0 = array(); // Результат возвращаемый от запроса
/*
* Returns the result set
*/
public function getResult()
{
return $this->result0;
}
Вообще класс пост, все красиво разложено.
Краше бы смотрелось:
public function __construct() {
if (!$this->link = mysql_connect(DB_HOST, DB_USER, DB_PASS)) {
trigger_error('Error: Could not make a database link using ' . DB_USER . '@' . DB_HOST);
return FALSE;
} else {
if (!mysql_select_db(DB_NAME, $this->link)) {
trigger_error('Error: Could not connect to database ' . DB_NAME);
return FALSE;
} else {
mysql_query("SET NAMES 'utf8'", $this->link);
mysql_query("SET CHARACTER SET utf8", $this->link);
mysql_query("SET CHARACTER_SET_CONNECTION=utf8", $this->link);
mysql_query("SET SQL_MODE = ''", $this->link);
return TRUE;
}
return TRUE;
}
}
<----------тут остальные методы------------>
public function __destruct() {
if (!mysql_close($this->link)){
return FALSE;
} else {
return TRUE;
}
}
тогда можно упростить инициализацию до
$db = new MySQL();
$res = $db->query('Select * from user');
а в select() красивее:
$i=0;
while ($row = mysql_fetch_assoc($res)) {
foreach ($row as $key => $value) {
$ret[$i][$key] = $value;
}
$i++;
}
Автору респектище!
Хотелось бы подписочку на новости!)
или в Select даже так if($query)
{
$this->numRows = mysql_num_rows($query);
$mass = Array();
for($i=0; $i<$this->numRows; $i++)
{
$r = mysql_fetch_assoc($query);
$mass[$i] = $r;
}
}
return $mass
я знаю что метод destruct() работает не совсем противоположно методу construct(). диструктор посылает запрос на уничтожение объекта а php машина в по очереди удаляет объекты! Поэтому думаю не очень удачный пример с диструктором! Если проект маленький и объектов немного, то да! но если объектов много , могут возникнуть проблемы!
Добрый день, в чем разница если мы будем использовать просто пользовательский функции для работы с БД? Почему удобнее использовать объекты в классе?
Спасибо!
Alfaroma, самый существенный плюс: этим вы СУЩЕСТВЕННО сократите объем своего кода, остальные не упомню, так как с php практически не работаю
Может я чего не понимаю, но смысл с такого класса, если данные возвращаются либо в многомерном, либо в одномерном массивах, которые приходится проверять, и выводить данные соответствующим способом, чтобы не получить "крякозябру". Или может какой-то магические способ есть, который одинаково хорошо работает и для многомерных и для одномерных массивов?
В функции select вместо отбора только ассоциативного массив,
if(!is_int($key[$x]))
не проще изначально добавить константу на выборку:
mysql_fetch_array($result, MYSQL_ASSOC)
I'm trying to create alike class, but using PDO (as PDO provides built-in security stuff against SQL injections). Check it out:
class db {
private $db_name = "";
private $username = "";
private $password = "";
private function dsn() {
return 'mysql:host=localhost;dbname='.$this->db_name.';charset=UTF8';
}
public function connect() {
$con = NULL;
try{
$con = new PDO($this->dsn(), $this->username, $this->password);
$con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e){
print 'ERROR: ' . $e->getMessage();
}
$this->con = $con;
}
public function con() {
return $this->con;
}
public function query($query, $params = null) {
$this->result = NULL;
try {
$stmt = $this->con->prepare($query);
if($params != NULL) {
foreach($params as $key=>$val) {
$stmt->bindParam($key+1, $val);
}
}
$stmt->execute();
$this->rowCount = $stmt->rowCount();
while ($result = $stmt->fetch(PDO::FETCH_NUM)) {
$this->result[] = $result;
}
$stmt = NULL;
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
}
}
Usage example:
$db = new db;
$db->connect();
$params[] = '2';//this value could be received from POST or GET. No need to be escaped. PDO does it for Y with bindParam() method.
$q = "select field, field1, field2 from mytable where field=?";
$db->query($q,$params);
Скажите, пожалуйста,как получить значения самого массива ?
Как изменить
<?php
include('crud.php');
$db = new Database();
$db->connect();
$db->select('mysqlcrud');
$res = $db->getResult();
print_r($res);
?>
чтобы получить значения?
В коде очень много нелепых синтаксических ошибок. Значит этот код не запускался и не решал реальные задачи.
Константин, код используется, но вы правы, пришлось немного дорабатывать, а вообще-то это перевод и исходный код я не менял в переводе
Здравствуйте!
Подскажите, пожалуйста, как построчно вывести данные ?
То есть я хочу их выводить как отдельные блоки, а не массивом.
Я имею ввиду этот участок
for ($i = 0; $i < $this->numResults; $i++) {
$r = mysql_fetch_array($query);
$key = array_keys($r);
for ($x = 0; $x < count($key); $x++) {
// Sanitizes keys so only alphavalues are allowed
if (!is_int($key[$x])) {
if (mysql_num_rows($query) > 1) {
$this->result[$i][$key[$x]] = $r[$key[$x]];
} else if (mysql_num_rows($query) < 1) {
$this->result = null;
} else {
$this->result[$key[$x]] = $r[$key[$x]];
}
}
}
}
Процедурным кодом я понимаю, как это сделать. но на ооп застрял
Разобрался.
Если кому интересно:
нужно заменить это:
$r = mysql_fetch_array($query);
$key = array_keys($r);
for($x = 0; $x < count($key); $x++)
{
// Sanitizes keys so only alphavalues are allowed
if(!is_int($key[$x]))
{
if(mysql_num_rows($query) > 1)
$this->result[$i][$key[$x]] = $r[$key[$x]];
else if(mysql_num_rows($query) < 1)
$this->result = null;
else
$this->result[$key[$x]] = $r[$key[$x]];
}
}
на это
$r = mysql_fetch_assoc($query);
echo 'id:' . $r['id'] . ', <br>имя: ' . $r['name'] . ',<br>Адрес:' .$r['email'] . '<br />';
И есть вопрос:
Можно как-то эти данные передавать в другую функцию?
Автор, обновите информацию! В документации указано, что ".. расширение mysql устарело, начиная с версии PHP 5.5.0, и удалено в PHP 7.0.0" Устарело и удалено!
sssr, во-первых, здесь не документация, во-вторых, смотрите на дату статьи, в-третьих, мне это неинтересно (не занимаюсь пхп)
борода