Форум программистов, компьютерный форум, киберфорум
PHP: ООП
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.67/9: Рейтинг темы: голосов - 9, средняя оценка - 4.67
0 / 0 / 0
Регистрация: 03.11.2014
Сообщений: 10

Общее свойство для всех классов

16.11.2014, 12:50. Показов 2027. Ответов 14
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Был у меня набор скриптов, которые производили определенные действия и всем им было нужно соединение с базой данных. Поэтому я сделал отдельный файл, в котором создал PDO, записал его в переменную $pdo, а потом этот файл в каждом скрипте подключал и преспокойно использовал $pdo->prepare ну и так далее. Вот-с.

Потом я решил все это дело получше структурировать и перепилить на ООП. Бывшие ранее отдельные скрипты сгруппировал и разместил по классам в виде методов. Однако им по-прежнему нужно соединение с БД и "тот самый $pdo, который бы позволял не писать каждый раз заново соединение с базой".

На примере объясню: вот есть класс, отвечающий за авторизацию, назовем его 'auth'. Он принимает, допустим, логин и далее должен сделать запрос к БД, чтобы его проверить. Если раньше я просто подключал файл и использовал $pdo, то здесь так не получится - надо либо в этом же классе создавать $pdo, либо же передавать извне уже готовый $pdo. Однако ни то, ни другое неверно с точки зрения логики, ибо задача соединения с БД вовсе не относится к классу 'auth'. Надо сделать как-то так, чтобы в этом классе уже было доступно соединение.

Собственно, вопрос: как же это сделать?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
16.11.2014, 12:50
Ответы с готовыми решениями:

Общее свойство (поле) у двух различных классов
Здравствуйте, необходимо реализовать два класса с различными свойствами (полями), где одно свойство (поле) у них будет общим (полагаю, это...

Глобальное для вложенных классов свойство
Здравствуйте, подскажите как правильно реализовать поле/свойство, которое будет доступно всем вложенным классам текущего класса? Чтобы...

Свойство background для ВСЕХ окон проекта
Привет. Столкнулся с проблемой: код помещенный в словарь ресурсов: <Style TargetType="Window"> <Setter...

14
504 / 247 / 75
Регистрация: 31.10.2010
Сообщений: 747
16.11.2014, 13:58
simmers, вот MISQLquery.zip класс на php сохраняет подключение к БД (MySQL),
понадобятся ещё функции записи сообщений об ошибках в файл, можно и без них если переделать алгоритм сообщений об ошибках.

Кликните здесь для просмотра всего текста
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//=========================================================================
// функция вывода сообщения об ошибке в соответствии с настройками системы
// Параметры:
//   $message - строка сообщения формат:
//   текст сообщения in file: файл on line: строка
// Возвращает:
//  выводит сообщение в файл или в (файл и терминал)
function MI_funcException( $message ) {
  $error_message = '['.date("d-m-Y H:i:s", time()).'] remote_addr:['.
                   $_SERVER['REMOTE_ADDR'].'] error: ['.$message.']';
  $display = ini_get('display_errors');
  if( ($display == 1) || ($display == 'on') )
    echo $error_message.'<br />';                 // если включен вывод на экран
  $filelog = ini_get('error_log');
  if( ($filelog == 1) || ($filelog == 'on') ) {   // если включен вывод в файл
    $patherlog = ini_get('error_log');
    MI_filewrite($patherlog, $error_message."\r\n");
  }
  return;
}
//=========================================================================
// функция записи (дозаписи) данных в локальный файл
// с блокировкой файла на время записи,
// для исключения возможности одновременного обращения
// Параметры:
//   $filename - имя файла
//   $data - строка данных
//   $rewrit - признак очистки файла перед записью (TRUE);
//   по умолчанию FALSE (дозапись)
// Возвращает:
//   $result - число записанных байт  данных или NULL - при ошибке
function MI_filewrite( $filename, $data, $rewrit = FALSE ) {
  $result = NULL;                          // начальное значение результата
  // Если файла нет, создаем пустой
  if( $handle = fopen($filename,"a+b") ) { // если файл открыт
    if( $data == "" ) $result  = 1;        // если передана пустая строка
    else {                                 // если передана не пустая строка
      if( flock($handle,LOCK_EX) ) {       // если заблокирован
        if( $rewrit ) {
          ftruncate( $handle, 0 );         // урезаем длину файла до нуля
          fseek( $handle, 0, SEEK_SET );   // позицию курсора в ноль
        }
        // записываем строку
        if( ($result=fwrite($handle,$data)) === FALSE )
          $result = NULL;   // если ошибка записи в файл
        else  fflush( $handle );           // очистка буфера
      }
      flock( $handle, LOCK_UN );           // снимаем блокировку
    }
    fclose( $handle );                     // закрытие файла
  }
  return( $result );                       // выход
}
//=========================================================================
1
504 / 247 / 75
Регистрация: 31.10.2010
Сообщений: 747
16.11.2014, 14:06
simmers, вот Вложение 454780 класс на php сохраняет подключение к БД (MySQL) даже при удалении класса за счёт статического массива,
PHP
1
2
  // статческий указатель на массив открытых соединений с БД
  private static $listdb = NULL;
,
подключений может быть много и все они сохраняются.
Программно каждый раз при создании класса подключаешься к БД но фактически подключение происходит только один раз, при первом обращении к БД, последующие обращения используют ранее созданные подключения.
все подключения возможно принудительно закрыть используя метод close_connect().

Добавлено через 1 минуту
simmers, понадобятся ещё функции записи сообщений об ошибках в файл, можно и без них если переделать алгоритм сообщений об ошибках.

Кликните здесь для просмотра всего текста
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//=========================================================================
// функция вывода сообщения об ошибке в соответствии с настройками системы
// Параметры:
//   $message - строка сообщения формат:
//   текст сообщения in file: файл on line: строка
// Возвращает:
//  выводит сообщение в файл или в (файл и терминал)
function MI_funcException( $message ) {
  $error_message = '['.date("d-m-Y H:i:s", time()).'] remote_addr:['.
                   $_SERVER['REMOTE_ADDR'].'] error: ['.$message.']';
  $display = ini_get('display_errors');
  if( ($display == 1) || ($display == 'on') )
    echo $error_message.'<br />';                 // если включен вывод на экран
  $filelog = ini_get('error_log');
  if( ($filelog == 1) || ($filelog == 'on') ) {   // если включен вывод в файл
    $patherlog = ini_get('error_log');
    MI_filewrite($patherlog, $error_message."\r\n");
  }
  return;
}
//=========================================================================
// функция записи (дозаписи) данных в локальный файл
// с блокировкой файла на время записи,
// для исключения возможности одновременного обращения
// Параметры:
//   $filename - имя файла
//   $data - строка данных
//   $rewrit - признак очистки файла перед записью (TRUE);
//   по умолчанию FALSE (дозапись)
// Возвращает:
//   $result - число записанных байт  данных или NULL - при ошибке
function MI_filewrite( $filename, $data, $rewrit = FALSE ) {
  $result = NULL;                          // начальное значение результата
  // Если файла нет, создаем пустой
  if( $handle = fopen($filename,"a+b") ) { // если файл открыт
    if( $data == "" ) $result  = 1;        // если передана пустая строка
    else {                                 // если передана не пустая строка
      if( flock($handle,LOCK_EX) ) {       // если заблокирован
        if( $rewrit ) {
          ftruncate( $handle, 0 );         // урезаем длину файла до нуля
          fseek( $handle, 0, SEEK_SET );   // позицию курсора в ноль
        }
        // записываем строку
        if( ($result=fwrite($handle,$data)) === FALSE )
          $result = NULL;   // если ошибка записи в файл
        else  fflush( $handle );           // очистка буфера
      }
      flock( $handle, LOCK_UN );           // снимаем блокировку
    }
    fclose( $handle );                     // закрытие файла
  }
  return( $result );                       // выход
}
//=========================================================================
1
0 / 0 / 0
Регистрация: 03.11.2014
Сообщений: 10
16.11.2014, 14:17  [ТС]
Спасибо конечно, но как-то там многовато всего, а вопрос на 5 копеек как говорится, да к тому же пользоваться готовыми решениями "это не наш метод". Я вот пока что так сделал:
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class engine{
        protected $srv = 'localhost';
        protected $dbn = 'тут_имя';
        protected $usr = 'тут_юзер';
        protected $pwd = 'тут_пароль';                
        protected $pdo;
                       
        protected function makeConnection(){
            try {
                $pdoDBsettings = 'mysql:host=' . $this->srv . '; dbname=' . $this->dbn;
                $this->pdo = new PDO($pdoDBsettings, $this->usr, $this->pwd, array(PDO::ATTR_PERSISTENT => true));
                $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                $this->pdo->exec("set names utf8");
            }
            catch(PDOException $e){
                //echo $e->getMessage();
            }            
        }
    }
 
    
 
    class autorizer extends engine{
        private $pass;
        
        function __construct(){
            $this->makeConnection();
        }
        
        function makeQuery(){
            $qry = $this->pdo->prepare("SELECT * FROM ts_accs");
            $qry->execute();
        }
    }
то есть я в конструкторе потомка просто вызываю метод, унаследованный от родителя и таким образом получаю заветный $pdo. Причем создается постоянное соединение, то есть, по идее, если я сделаю еще несколько классов и в их конструкторах аналогично вызову метод makeConnection(), то будет использовано старое соединение, которое получилось при самом первом вызове метода.
На вид вроде бы нормально, как считаете? Или говнарьство?
0
504 / 247 / 75
Регистрация: 31.10.2010
Сообщений: 747
16.11.2014, 14:44
simmers, лучше используй статические переменные они доступны всегда даже до создания класса и после его разрушения
private static $namevar;

Добавлено через 14 минут
simmers, из плюсов:
- параметры подключения заданы в классе, это хорошее повышение безопасности кода.
из минусов:
- нет возможности подключения к нескольким БД;
- чем больше иерархия классов тем медленнее это всё работает;
- при уничтожении родительского класса или дочернего соединение потеряется, т.е. необходимо хранить в памяти весь объект, а не только подключение к БД.

При создании новых объектов будут создаваться новые подключения, кроме того не предусмотрено корректное закрытие соединения.

Посмотри как сделано здесь Вложение 454780, используй принцип
1
0 / 0 / 0
Регистрация: 03.11.2014
Сообщений: 10
16.11.2014, 19:01  [ТС]
То есть вот так чтоли примерно?

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//файл с классами
    class engine{
        protected static $srv = 'localhost';
        protected static $dbn = 'база';
        protected static $usr = 'юзер';
        protected static $pwd = 'пароль';
        public static $pdo;
 
        public static function makeConnection(){
            try {
                $pdoDBsettings = 'mysql:host=' . self::$srv . '; dbname=' . self::$dbn;
                self::$pdo = new PDO($pdoDBsettings, self::$usr, self::$pwd, array(PDO::ATTR_PERSISTENT => true));
                self::$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                self::$pdo->exec("set names utf8");
            }
            catch(PDOException $e){
                //echo $e->getMessage();
            }            
        }
    }
 
    
 
    class autorizer{
        private $pass;
  
        function makeQuery(){
            $qry = engine::$pdo->prepare("SELECT * FROM ts_accs");
            $qry->execute();
        }
    }
 
//файл index.php
 
    engine::makeConnection();
    $aut = new autorizer();
    $aut->makeQuery();
0
504 / 247 / 75
Регистрация: 31.10.2010
Сообщений: 747
16.11.2014, 19:13
simmers, да так уже лучше, только подключение всё равно каждый раз будет новым, смотри внимательно код который я прикреплял ранее, там при каждом создании объекта БД происходит поиск, имеется ли такое подключение, если имеется то используется готовое, если нет то подключаемся вновь.

статическим достаточно сделать объект подключения
PHP
1
public static $pdo;
остальные переменные нет смысла делать статическими, кроме того для создания возможности множества подключений $pdo лучше организовать как массив, каждый элемент которого.
На форуме благодарность принято выражать отмечая ответы.
1
0 / 0 / 0
Регистрация: 03.11.2014
Сообщений: 10
16.11.2014, 19:36  [ТС]
Но pdo сам ищет доступные соединения, то есть вот я создал один раз pdo, и он после выполнения скрипта закэшировался. Когда в следующий раз снова создается pdo, он проверяет кэш и если там есть уже соединение с такими же параметрами, то он его просто берет, а новое не создает.

А как отмечать ответы ты говоришь для благодарности?

А, вот еще, забыл спросить: почему только $pdo надо делать статическим? Ведь если я не сделаю статическими остальные свойства, то их нельзя будет использовать в статическом методе.
0
504 / 247 / 75
Регистрация: 31.10.2010
Сообщений: 747
16.11.2014, 19:49
Цитата Сообщение от simmers Посмотреть сообщение
Ведь если я не сделаю статическими остальные свойства, то их нельзя будет использовать в статическом методе.
, если ты будешь создавать объект, то все переменные создадутся нет смысла хранить их в статическом виде. В статическом виде есть смысл хранить только указатель на объект подключения к БД, что бы соединение сохранялось.
Если PDO кеширует соединения, то нет смысла вобще применять статические объекты просто не закрывать соединение, при следующем соединении с БД оно найдётся в кеше и PDO использует имеющееся (только если PDO точно кеширует, ты уверен в этом?).
0
365 / 372 / 89
Регистрация: 01.12.2013
Сообщений: 1,629
16.11.2014, 20:29
Цитата Сообщение от simmers Посмотреть сообщение
то есть вот я создал один раз pdo, и он после выполнения скрипта закэшировался
Че правда?

Добавлено через 1 минуту
Цитата Сообщение от simmers Посмотреть сообщение
Когда в следующий раз снова создается pdo, он проверяет кэш и если там есть уже соединение с такими же параметрами, то он его просто берет, а новое не создает.
Боролись за ооп, а пришли к говнокоду?
0
0 / 0 / 0
Регистрация: 03.11.2014
Сообщений: 10
16.11.2014, 20:31  [ТС]
Уверен, что кэширует, это точно, но только в том случае, если при создании указывать array(PDO::ATTR_PERSISTENT => true), а я указал.

А зачем мне создавать объект engine? Если я его создам даже, то это ничего не даст, потому что метод makeConnection я все равно не смогу использовать через объект. А если, например, добавлю обычный метод, который меняет параметры соединения (хост, бд, юзер, пароль), и через объект его вызову, то измененные свойства статический метод не увидит.

Фуск, что-то я совсем запутался. Так что значит, раз pdo кэширует, то мне возвращать как было, без статических?
0
365 / 372 / 89
Регистрация: 01.12.2013
Сообщений: 1,629
16.11.2014, 20:36
Цитата Сообщение от simmers Посмотреть сообщение
почему только $pdo надо делать статическим
зачем? Всегда есть класс уровня приложения в котором может быть свойство отвечающее за базу данных. PDO в вашем случае. Туда ваше пдо и сохраняйте. А вообще бред. Вам дают готовый класс PDO для работы с базой данных, а вы его заворачиваете в другой класс. Сами себе ответьте : Нафига?

Добавлено через 1 минуту
Цитата Сообщение от simmers Посмотреть сообщение
PDO::ATTR_PERSISTENT
тем более невиг его в свой класс запихивать.

Добавлено через 42 секунды
только больше путаницы себе сделаете
0
0 / 0 / 0
Регистрация: 03.11.2014
Сообщений: 10
16.11.2014, 20:39  [ТС]
Правда. Вот пруф https://php.net/manual/ru/pdo.connections.php
"Постоянные соединения не закрываются при завершении работы скрипта, они кэшируются и используются повторно, когда другой скрипт запрашивает соединение с теми же учетными данными. "
PHP
1
2
3
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(
    PDO::ATTR_PERSISTENT => true
));
Я потому и спросил как лучше. Если делать через статические, то можно один раз написать вызов метода класса engine::makeConnection(); и дальше уже engine::$pdo использовать во всех других объектах. То есть вся конструкция
PHP
1
2
3
4
5
6
7
8
9
try {
                $pdoDBsettings = 'mysql:host=' . self::$srv . '; dbname=' . self::$dbn;
                self::$pdo = new PDO($pdoDBsettings, self::$usr, self::$pwd, array(PDO::ATTR_PERSISTENT => true)); //установить ПОСТОЯННОЕ соединение к базой данных
                self::$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                self::$pdo->exec("set names utf8");                
            }
            catch(PDOException $e){
                echo $e->getMessage();
            }
будет вызвана только один раз. Если делать без статических, то надо просто все классы, где нужен Pdo, делать наследниками engine и в их конструкторе вызывать указанный выше код (ну не сам код вернее, а метод, в котором он написан, makeConnection() то есть). Плюс в том, что уже не нужно писать ничего дополнительного, просто создаешь нужный объект и все, pdo в нем уже есть.
0
365 / 372 / 89
Регистрация: 01.12.2013
Сообщений: 1,629
16.11.2014, 20:40
php парадоксальный язык нарушающий все правила в том числе и ооп. По ооп если вы создаете новый экзампляр класса, то все нестатические члены создаются заново. в том числе и соединения. Из этого утверждения нужно исходить. Если вы рассчитываете на парадоксальность языка и ее используете - хорошего в результате не ждите. Будете иметь ошибки. Я не так хорошо знаю пых, но как должно работать ооп знаю. Во многих языках работает, а в пыхе - ошибка.
0
0 / 0 / 0
Регистрация: 03.11.2014
Сообщений: 10
16.11.2014, 20:53  [ТС]
>>Вам дают готовый класс PDO для работы с базой данных, а вы его заворачиваете в другой класс.

Так мне же и нужно создать объект этого класса. Как я буду этот класс-то без объекта использовать?

Я напишу полностью, чтобы было окончательно понятно. Что задумывалось: есть много классов, которые отвечают за что-то свое, в частности - один за авторизацию, другой за выполнение заказов, третий за оформление заказа и так далее. Всем им нужно соединение с базой данных. Раньше, когда классов не было, говорю, у меня был файл, где объявлена переменная $pdo, в которую создавался объект PDO. Дальше я этот файл подключал в каждом файле скрипта и пользовался переменной $pdo, чтобы каждый раз не писать все это new PDO бла-бла-бла. А когда я перешел на классы, мне понадобился аналог этой переменной $pdo, чтобы был тот же эффект. Я так чувствую, что просто вы не допонимаете, о чем я говорю. Мне сейчас нужно, чтобы я создал экземпляр класса auth, который отвечает за авторизацию, и в нем мог написать, грубо говоря, $qry = $pdo->prepare('запрос'). Вот что надо. В связи с этим и возник вопрос - как сделать надо, чтоб это не было по-говнарьски, а по-человечески.

Добавлено через 3 минуты
Смысла нет создавать объект класса, в котором сделано соединение с бд. Потому что в этом классе нет никакого функционала, кроме этого соединения, а соединение делается в статическом методе и сохраняется в статическую переменную.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
16.11.2014, 20:53
Помогаю со студенческими работами здесь

Сабклассинг. Общее Popup меню для всех форм проекта
Возможно ли создать своё Popup меню, общее для всех TextBox'ов проекта, находящихся на разных формах? В пределах одной формы я умею...

Как сделать общее системное меню для всех активностей?
в андроиде пока не сильно ориентируюсь. хочется сделть общее меню на все приложение в таком виде, как на примере не работает. ...

Как изменить свойство формы для всех форм проекта?
Собственно САБЖ. Был создан проект в ходе реализации было создано более 30 форм , есть ли возможность изменить у всех форм например...

Найти самое длинное общее слово для всех предложений текста
Помогите с решением задачи: Найти самое длинное общее слово для всех предложений текста, текст берется из memo.

Основной класс, для наследования от него данных для всех остальных классов
Здравствуйте, как удобным способом сделать класс в котором будут проинициализированы некоторые поля (например, имя сервера к которому...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Новые блоги и статьи
Уведомление о неверно выбранном значении справочника
Maks 06.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "НарядПутевка", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если в документе выбран неверный склад. . .
Установка Qt Creator для C и C++: ставим среду, CMake и MinGW без фреймворка Qt
8Observer8 05.04.2026
Среду разработки Qt Creator можно установить без фреймворка Qt. Есть отдельный репозиторий для этой среды: https:/ / github. com/ qt-creator/ qt-creator, где можно скачать установщик, на вкладке Releases:. . .
AkelPad-скрипты, структуры, и немного лирики..
testuser2 05.04.2026
Такая программа, как AkelPad существует уже давно, и также давно существуют скрипты под нее. Тем не менее, прога живет, периодически что-то не спеша дополняется, улучшается. Что меня в первую очередь. . .
Отображение реквизитов в документе по условию и контроль их заполнения
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеСпецтехники", разработанного в конфигурации КА2. Данный документ берёт данные из другого нетипового документа. . .
Фото всей Земли с борта корабля Orion миссии Artemis II
kumehtar 04.04.2026
Это первое подобное фото сделанное человеком за 50 лет. Снимок называют новым вариантом легендарной фотографии «The Blue Marble» 1972 года, сделанной с борта корабля «Аполлон-17». Новое фото. . .
Вывод диалогового окна перед закрытием, если документ не проведён
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: реализовать программный контроль на предмет проведения документа. . .
Программный контроль заполнения реквизитов табличной части документа
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: 1. Реализовать контроль заполнения реквизита. . .
wmic не является внутренней или внешней командой
Maks 02.04.2026
Решение: DISM / Online / Add-Capability / CapabilityName:WMIC~~~~ Отсюда: https:/ / winitpro. ru/ index. php/ 2025/ 02/ 14/ komanda-wmic-ne-naydena/
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru