[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Упростить класс.
m4a1fox
Итак господа, всем доброго вечера. Я не знаю как кто пишет код, но а я пишу по следующей схеме. Набрасываем что-то общее, а после начинаю резать. Так как код, кот. вы уведите может поразить своим уродством, то прошу строго не судить и не кричать, ибо - это общий план класса, а теперь его нужно порезать. Разумеется, я сам попробую упростить как только получится... но если кто из вас поможет в этом, буду только благодарен. Итак. Имеем такой "класс"

<?php
class
Database extends PDO{
public function __construct($dbdriver, $hostname, $dbname, $username, $password, $char_set){
try{
parent::__construct($dbdriver . "::host=". $hostname ."; dbname=".$dbname, $username, $password,
array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES '.$char_set));

parent::setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}catch(PDOException $e){
include './views/exception/index.php';
exit();
}
}


public function insert($table, $data){
ksort($data);

$fieldNames = implode('`, `', array_keys($data));
$fieldValues = ':' . implode(', :', array_keys($data));
try{
$stn = $this->prepare("INSERT INTO `$table` (`$fieldNames`) VALUES($fieldValues)");

foreach($data as $key=>$value){
$stn->bindValue(":$key", $value);
}

$stn->execute();
}catch(Exception $e){
include './views/exception/index.php';
exit();
}
}



public function selectAll($table){
try{
$sql = $this->query("SELECT * FROM `$table`");
while($res = $sql->fetch(PDO::FETCH_ASSOC)){
$ar = new stdClass();
foreach ($res as $key=>$value)
$ar->$key = $value;
$data[] = $ar;
}
return $data;
}catch(Exception $e){
include './views/exception/index.php';
exit();
}
}


public function selectSingle($table, $where){
$sql = $this->query("SELECT * FROM `$table` WHERE $where");
$res = $sql->fetch(PDO::FETCH_ASSOC);
$ar = new stdClass();
foreach ($res as $key=>$value)
$ar->$key = $value;
$data[] = $ar;
return $data;
}


public function update($table, $data, $where){
ksort($data);
$str = implode(', ', array_map(function($str){return '`'.$str.'` = :'.$str;}, array_keys($data)));
$stn = $this->prepare("UPDATE $table SET $str WHERE $where");
$stn->execute($data);
}

public function updateMulti($table, $data, $where){
try{
if(count($data) > 0){
foreach($data as $val){
if(!in_array($where, array_keys($val))){
throw new Exception('Wrong field where');
exit();
}
$ar = array_map(function($str){return '`'.$str.'` = :'.$str;}, array_keys($val));
$row = implode(', ', array_values($ar));
$stn = $this->prepare("UPDATE $table SET $row WHERE `$where` = ".$val[$where]);
$stn->execute($val);
}
}
else{
throw new Exception('Data is empty');
exit();
}
}
catch(PDOException $e){
include './views/exception/index.php';
exit();
}catch(Exception $e){
include './views/exception/index.php';
exit();
}
}


public function delete($table, $data){
$fieldValues = implode(', ', array_map(function($str){return '`'.$str.'` = :'.$str;}, array_keys($data)));
try{
$stn = $this->prepare("DELETE FROM $table WHERE $fieldValues");

foreach($data as $key=>$value){
$stn->bindValue(":$key", $value);
}

$stn->execute();
}catch(Exception $e){
include './views/exception/index.php';
exit();
}
}


public function emptyTable($table){
$stn = $this->prepare("TRUNCATE TABLE $table");
return $stn->execute();
}
}


Как видите, все довольно тривиально и просто. В классе несколько методов, и конечно же как то не красиво на всем этом фоне выделяется исключения (это первый опыт). Что же умеет класс?
1. Выбирать из таблицы БД все данные и все строки.
2. Выбирать из таблицы БД строго заданную строку.
3. Вставлять данные в таблицу БД.
4. Обновлять данные в таблице в БД строго одну строчку
5. Обновлять данные в таблице в БД несколько строк (массив)
6. Удалять данные из таблицы в БД строго одну строчку.
7. Очищать полностью таблицу.

В принципе и так все работает более-менее, но смотрится уж больно коряво.
Мнение приветствуются.
-----------------------------------------------------------------------------------------------
Пожалуй, я начну первый :)
Сразу бросается в глаза одно из повторений вот такой команды

implode(', ', array_map(function($str){return '`'.$str.'` = :'.$str;}, array_keys($data)));


Логичнее ее наверно вынести отдельно в какой-нибудь метод, и потом просто вызывать через $this?



Спустя 19 минут, 41 секунда (30.03.2012 - 18:38) m4a1fox написал(а):
I'll be back! Very soon.

Спустя 11 минут, 23 секунды (30.03.2012 - 18:49) johniek_comp написал(а):
А почему у тебя не везде ` стоит? :o

И я бы предпочитал такой стиль, уж больно хорошо читается
class simple
{
public static function johniek()
{
return;
}

}

чем такой
class simple {
public static function johniek() {
return;
}

}

Спустя 10 минут, 50 секунд (30.03.2012 - 19:00) Oyeme написал(а):
Вот что мне бросается в глаза.Попробуйте сами догадаться почему я выделил именно эти моменты кода.

1.
}catch(PDOException $e){
include './views/exception/index.php';
exit();
}

catch(Exception $e){
include './views/exception/index.php';
exit();
}


2.
 include './views/exception/index.php';

3.
 $ar = new stdClass();
foreach ($res as $key=>$value)
$ar->$key = $value;
$data[] = $ar;


4.
In update
 if(count($data) > 0){
...
}


}



Updated
Fetch all data

 public function selectAll($table){

}


http://php.net/manual/en/pdostatement.fetchall.php

The method insert should return the last inserted id.
http://pt2.php.net/manual/en/pdo.lastinsertid.php

Спустя 48 минут, 10 секунд (30.03.2012 - 19:48) m4a1fox написал(а):
johniek_comp
Цитата
А почему у тебя не везде ` стоит? ohmy.gif

Конкретнее говори.
Цитата
И я бы предпочитал такой стиль, уж больно хорошо читается

Каждый дро...т как он хочет.

Спустя 2 минуты, 1 секунда (30.03.2012 - 19:50) m4a1fox написал(а):
Oyeme
Цитата

}catch(PDOException $e){            
include './views/exception/index.php';           
exit();       
}   
catch(Exception $e){           
include './views/exception/index.php';           
exit();       
}


Наверно так можно
}catch(PDOException $e || Exception $e){            
include './views/exception/index.php';
exit();
}

Спустя 8 минут, 48 секунд (30.03.2012 - 19:59) glock18 написал(а):
Цитата (m4a1fox @ 30.03.2012 - 17:50)
}catch(PDOException $e || Exception $e){           
include './views/exception/index.php';           
exit();       
}


ты же не думаешь, что пых на это не выругается? вообще, полагаю комментарий Oyeme в первую очередь относился к этому

include './views/exception/index.php';

много уже таких инклюдов? в каждом файле путь вручную подгоняете под нужный уровень?

а упомянутые два catch и правда можно записать одним, но не так, как вы написали.

Спустя 1 час, 34 минуты, 27 секунд (30.03.2012 - 21:34) m4a1fox написал(а):
glock18
Цитата
много уже таких инклюдов? в каждом файле путь вручную подгоняете под нужный уровень?

Нет, не много. Как такие исключения я надеюсь вылавливать только в этом файле. Итого 4 инклюдов...

Надо как то этот момент продумать, а то и в правду как то не правильно получается...

Цитата
а упомянутые два catch и правда можно записать одним, но не так, как вы написали.

Если можно, то намек бы как правильно сделать? Или где про это почитать?

Спустя 1 час, 16 минут (30.03.2012 - 22:50) m4a1fox написал(а):
Продолжаем воевать.
Имеем вот такой селект

public function selectAll($table){
$sql = $this->query("SELECT * FROM `$table`");
while($res = $sql->fetch(PDO::FETCH_ASSOC)){
$ar = new stdClass();
foreach ($res as $key=>$value){
$ar->$key = $value;
}
$data[] = $ar;
}
return $data;
}

Вот такой вывод он вернет, к примеру

Array
(
[0] => stdClass Object
(
[id] => 1
[name] => Max
)

[1] => stdClass Object
(
[id] => 2
[name] => Oleg
)

[2] => stdClass Object
(
[id] => 3
[name] => Vika
)

[3] => stdClass Object
(
[id] => 4
[name] => Vika
)

)


Как правильно подметил Oyeme, есть же fetchAll вместо while. Итак. Применяем.
        $sql = $this->query("SELECT * FROM `$table`");
$res = $sql->fetchAll(PDO::FETCH_ASSOC);
$ar = new stdClass();
foreach ($res as $key=>$value){

$ar->$key = $value;
}
$data[] = $ar;
return $ar;

И на выходе имеем
stdClass Object
(
[0] => Array
(
[id] => 1
[name] => Max
)

[1] => Array
(
[id] => 2
[name] => Oleg
)

[2] => Array
(
[id] => 3
[name] => Vika
)

[3] => Array
(
[id] => 4
[name] => Vika
)

)

Как вы можете заметить вывод не идентичен к сожалению.... вопрос... как сделать его идентичным?

Спустя 2 минуты, 50 секунд (30.03.2012 - 22:52) ADiel написал(а):
PDO::FETCH_CLASS

Спустя 6 минут, 24 секунды (30.03.2012 - 22:59) m4a1fox написал(а):
Все проще
$sql = $this->query("SELECT * FROM `$table`");
$res = $sql->fetchAll(PDO::FETCH_CLASS, "stdClass");

foreach ($res as $key=>$value){

$ar[] = $value;
}

return $ar;

Спустя 7 минут, 28 секунд (30.03.2012 - 23:06) m4a1fox написал(а):
Как оказалось. все еще проще

$sql = $this->query("SELECT * FROM `$table`");
$res = $sql->fetchAll(PDO::FETCH_CLASS, "stdClass");
return $res;

----------------------------------------------
Как оказалось, спс ADiel все еще проще :)

$sql = $this->query("SELECT * FROM `$table`");
return $sql->fetchAll(PDO::FETCH_CLASS, "stdClass");

Спустя 3 минуты, 36 секунд (30.03.2012 - 23:10) Placido написал(а):
Еще проще:
$sql = $this->query("SELECT * FROM `$table`");
$res = $sql->fetchAll(PDO::FETCH_OBJ);
return $res;

Спустя 6 минут, 5 секунд (30.03.2012 - 23:16) m4a1fox написал(а):
Placido
Ух ты.... проверю сейчас!
Как! Ну как оно работает?

Спустя 21 минута, 2 секунды (30.03.2012 - 23:37) Placido написал(а):
При PDO::FETCH_OBJ результаты возвращаются в виде объектов класса stdClass.

Спустя 8 минут, 46 секунд (30.03.2012 - 23:46) m4a1fox написал(а):
Placido
О как! Сильно! Спасибо!

Спустя 4 минуты, 2 секунды (30.03.2012 - 23:50) m4a1fox написал(а):
Теперь оба селекта вот так выглядят
    public function selectMulti($table){
try{
$sql = $this->query("SELECT * FROM `$table`");
return $sql->fetchAll(PDO::FETCH_CLASS, "stdClass");
}catch(Exception $e){
include './views/exception/index.php';
exit();
}
}



public function selectSingle($table, $where){
$sql = $this->query("SELECT * FROM `$table` WHERE $where");
return $sql->fetch(PDO::FETCH_OBJ);
}

Спустя 23 часа, 18 минут, 34 секунды (1.04.2012 - 23:08) SlavaFr написал(а):
в классе которым как я пологаю ты или другие собераются пользоватся exit и include в catch блоке вредны. просто кидай ексепцию дальше, a ловить ее и думать что делать в случае ошибки при применение твоего класса.

Спустя 17 секунд (1.04.2012 - 23:09) Dezigo написал(а):
Чем Вас не устраивает подход реализации ?
DB::query("SELECT * FROM table ")->toRow();
DB::query("SELECT * FROM table ")->toArray();


Использовать
include './views/exception/index.php';

внутри класса ужасно не красиво,не делайте так.
Я отвечаю на интерестные вопросы только. :)

Спустя 1 час, 23 минуты, 36 секунд (2.04.2012 - 00:32) m4a1fox написал(а):
Dezigo
Цитата
внутри класса ужасно не красиво,не делайте так.

Согласен полностью. Но из-за нехватки навыков работы с исключениями, такой способ пока что достигнут лично... я просто с трудом могу представить как правильно... мож есть где почитать про это? Я просто найти не могу именно правильную реализацию отлова исключений.

Спустя 10 часов, 24 минуты, 31 секунда (2.04.2012 - 10:57) SoMeOnE написал(а):
Свернутый текст
Цитата (johniek_comp @ 30.03.2012 - 16:49)
И я бы предпочитал такой стиль, уж больно хорошо читается
class simple
{
    public static function johniek()
    {
        return;
    }

}

чем такой
class simple {
    public static function johniek() {
        return;
    }

}

И с чего это такая уверенность. Ну очень интересно...?

Спустя 3 минуты, 23 секунды (2.04.2012 - 11:00) Invis1ble написал(а):
каждый пишет как хочет, строгих правил не существует, всего лишь рекомендации и стандарты внутри определенных групп
я например и так и так пишу

Спустя 1 час, 45 минут, 27 секунд (2.04.2012 - 12:46) m4a1fox написал(а):
Да тут даже не правила а именно удобства лично для каждого свои. Где то, кажется на вики есть даже статья о стилях написания... и там каждый стиль даже вроде как то называется... Сейчас посмотрю, вдруг найду статейку.
Нашел - тут
Я кодирую стилем - «K&R»
Цитата
Назван в честь Кернигана и Ричи из-за того, что все примеры из их книги «Язык программирования Си» (нередко обозначаемой как просто «K&R» по инициалам авторов) отформатированы подобным образом. Также известен как «kernel style» (BSD KNF; из-за того, что ядро UNIX написано на нём), а также как «Единственный Правильный Скобочный Стиль» (англ. One True Brace Style - 1TBS) со слов его приверженцев. Основной отступ, показанный ниже, состоит из 8 пробелов (или одной табуляции) на уровень. Хотя чаще всего используется 4 пробела.

if (<cond>) {
········<body>
}


Спустя 3 дня, 23 часа, 16 минут, 20 секунд (6.04.2012 - 12:02) m4a1fox написал(а):
Было:
Свернутый текст


<?php
class
Database extends PDO{
public function __construct($dbdriver, $hostname, $dbname, $username, $password, $char_set){
try{
parent::__construct($dbdriver . "::host=". $hostname ."; dbname=".$dbname, $username, $password,
array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES '.$char_set));

parent::setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}catch(PDOException $e){
include './views/exception/index.php';
exit();
}
}


public function insert($table, $data){
ksort($data);

$fieldNames = implode('`, `', array_keys($data));
$fieldValues = ':' . implode(', :', array_keys($data));
try{
$stn = $this->prepare("INSERT INTO `$table` (`$fieldNames`) VALUES($fieldValues)");

foreach($data as $key=>$value){
$stn->bindValue(":$key", $value);
}

$stn->execute();
}catch(Exception $e){
include './views/exception/index.php';
exit();
}
}



public function selectAll($table){
try{
$sql = $this->query("SELECT * FROM `$table`");
while($res = $sql->fetch(PDO::FETCH_ASSOC)){
$ar = new stdClass();
foreach ($res as $key=>$value)
$ar->$key = $value;
$data[] = $ar;
}
return $data;
}catch(Exception $e){
include './views/exception/index.php';
exit();
}
}


public function selectSingle($table, $where){
$sql = $this->query("SELECT * FROM `$table` WHERE $where");
$res = $sql->fetch(PDO::FETCH_ASSOC);
$ar = new stdClass();
foreach ($res as $key=>$value)
$ar->$key = $value;
$data[] = $ar;
return $data;
}


public function update($table, $data, $where){
ksort($data);
$str = implode(', ', array_map(function($str){return '`'.$str.'` = :'.$str;}, array_keys($data)));
$stn = $this->prepare("UPDATE $table SET $str WHERE $where");
$stn->execute($data);
}

public function updateMulti($table, $data, $where){
try{
if(count($data) > 0){
foreach($data as $val){
if(!in_array($where, array_keys($val))){
throw new Exception('Wrong field where');
exit();
}
$ar = array_map(function($str){return '`'.$str.'` = :'.$str;}, array_keys($val));
$row = implode(', ', array_values($ar));
$stn = $this->prepare("UPDATE $table SET $row WHERE `$where` = ".$val[$where]);
$stn->execute($val);
}
}
else{
throw new Exception('Data is empty');
exit();
}
}
catch(PDOException $e){
include './views/exception/index.php';
exit();
}catch(Exception $e){
include './views/exception/index.php';
exit();
}
}


public function delete($table, $data){
$fieldValues = implode(', ', array_map(function($str){return '`'.$str.'` = :'.$str;}, array_keys($data)));
try{
$stn = $this->prepare("DELETE FROM $table WHERE $fieldValues");

foreach($data as $key=>$value){
$stn->bindValue(":$key", $value);
}

$stn->execute();
}catch(Exception $e){
include './views/exception/index.php';
exit();
}
}


public function emptyTable($table){
$stn = $this->prepare("TRUNCATE TABLE $table");
return $stn->execute();
}
}



Стало:
Свернутый текст


<?php
class
Database extends PDO{
public function __construct($dbdriver, $hostname, $dbname, $username, $password, $char_set){
try{
parent::__construct($dbdriver . "::host=". $hostname ."; dbname=".$dbname, $username, $password,array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES '.$char_set));

parent::setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}catch(PDOException $e){
exception_handler($e->getMessage(), 'Ошибка подключения к БД');
exit();
}
}


public function insert($table, $data){
$row = $this->generalImplodeArray($data);
$stn = $this->prepare("INSERT INTO `$table` SET $row ");
$stn->execute($data);
return $this->lastInsertId();
}

public function insertMulti($table, $data){
foreach($data as $key=>$value){
$this->insert($table, $value);
}
}


public function select($table, $where){
$sql = $this->query("SELECT * FROM `$table` WHERE $where");
return $sql->fetch(PDO::FETCH_OBJ);
}

public function selectMulti($table){
$sql = $this->query("SELECT * FROM `$table`");
return $sql->fetchAll(PDO::FETCH_CLASS, "stdClass");

}

public function update($table, $data, $where){
$str = $this->generalImplodeArray($data);
$stn = $this->prepare("UPDATE $table SET $str WHERE $where");
$stn->execute($data);
}

public function updateMulti($table, $data, $where){
foreach($data as $val){
$row = $this->generalImplodeArray($val);
$stn = $this->prepare("UPDATE $table SET $row WHERE `$where` = ".$val[$where]);
$stn->execute($val);
}
}


public function delete($table, $data){
$row = $this->generalImplodeArray($data);
$stn = $this->prepare("DELETE FROM $table WHERE $row");
$stn->execute($data);
}


public function cleanTable($table){
$stn = $this->prepare("TRUNCATE TABLE $table");
return $stn->execute();
}


private function generalImplodeArray($data){
ksort($data);
return implode(', ', array_map(function($str){return '`'.$str.'` = :'.$str;}, array_keys($data)));
}
}



Высказывайтесь!

Спустя 8 минут, 33 секунды (6.04.2012 - 12:10) Placido написал(а):
PDO::FETCH_CLASS, "stdClass" == PDO::FETCH_OBJ

Спустя 3 минуты, 40 секунд (6.04.2012 - 12:14) m4a1fox написал(а):
Placido
Цитата
PDO::FETCH_CLASS, "stdClass" == PDO::FETCH_OBJ

Да да... я помню Вы говорили! Но решил так, мотивируя это тем, что вполне возможно тут есть реальный шанс вписать не только stdClass, а и другой. Наверно. Хотя я могу и ошибаться!
Ну а общее мнение, Placido, можно ваше услышать?! Мне интересно просто, не зря я его переделывал?!

Спустя 10 часов, 30 минут (6.04.2012 - 22:44) Placido написал(а):
Высказать можно, но это будет чистое имхо, так как я сам только учусь.

То что бросилось в глаза:

- если используются подготовленные выражения, то где bindParam/bindValue? Тем более, что generalImplodeArray() возвращает строку с плейсхолдерами. Отсюда делаю вывод, что апдейты не рабочие. В случае инсертов тоже bindParam/bindValue не помешают, иначе нужно экранировать входящие данные вручную, а этого в коде тоже нет.

- экранирование переменной с именем таблицы обратными апострофами (`$table`) не спасет от инъекции. Подумайте, что будет, если в $table придет строка вида
$table = 'имя таблицы`; DROP TABLE `имя таблицы`; -- ';

Спустя 12 минут (6.04.2012 - 22:56) m4a1fox написал(а):
Placido
Ага! Понял! Если посмотреть на то что было, там как раз-то и есть bindParam/bindValue. Но! Я не увидел их реально пользы! То есть, к примеру имеем такой код:

foreach($data as $key=>$value){
$stn->bindValue(":$key", $value);
}

И вот такой
$stn->execute($data);

Что вернет первый вариант а что второй?
Я именно не могу сравнить! То есть увидеть реальную пользу!

Спустя 25 минут, 33 секунды (6.04.2012 - 23:22) Placido написал(а):
Использование bindValue/bindParam помогает предотвратить SQL-инъекции, если же этого нет, то необходимо фильтровать входящие данные вручную.

Спустя 4 минуты, 38 секунд (6.04.2012 - 23:26) m4a1fox написал(а):
Placido
Цитата
Использование bindValue/bindParam помогает предотвратить SQL-инъекции, если же этого нет, то необходимо фильтровать входящие данные вручную.

Да да! Это я читал! Реально покажи как! То есть чистый эксперимент! Берем строку (nic'k) и обрабатываем ее с помощью bindValue/bindParam... и после без нее...

Спустя 42 минуты, 13 секунд (7.04.2012 - 00:08) Placido написал(а):
Я уже пробовал, поверь мне на слово, что в случае prepare - execute без bind...() и фильтрования входящих данных инъекции проходят. Можешь поэкспериментировать.

Спустя 14 минут, 38 секунд (7.04.2012 - 00:23) m4a1fox написал(а):
Да я верю. Не зря же они придуманы. Проверить как то сложновато. Как бы так строку попробовать занести что бы без бинд она не прошла а с бинд экранировалась...

Спустя 13 минут, 20 секунд (7.04.2012 - 00:36) Placido написал(а):
Для селекта ("SELECT ... WHERE '$string' "):
$string = "whatever' OR 1+1; -- ";
Все, я - спать.

Спустя 12 дней, 10 часов, 16 минут, 40 секунд (19.04.2012 - 10:53) seyfer написал(а):
m4a1fox

Хотелось бы пример использования каждого метода. Входные данные и строка вызова.

Спустя 4 минуты, 37 секунд (19.04.2012 - 10:58) m4a1fox написал(а):
seyfer
Ну блин.... там же просто до ужаса... честно. Присмотрись. Давай ты попробуй... а я если что поправлю тебя.

Спустя 26 минут, 53 секунды (19.04.2012 - 11:25) seyfer написал(а):
m4a1fox

У меня реализовано иначе. Мне тоже как-то ленно. Я хотел что-то вроде этого

$query = "SELECT * FROM pro_articles
WHERE id_article = :id"
;

$param = array(
"id" => $id_article
);

$article = $this->DB->Select($query, $param);


т.е. вид данных и вызов.
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2025 Invision Power Services, Inc.