Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737
Форумы портала PHP.SU :: Как правильно запускать функцию?

 PHP.SU

Программирование на PHP, MySQL и другие веб-технологии
PHP.SU Портал     На главную страницу форума Главная     Помощь Помощь     Поиск Поиск     Поиск Яндекс Поиск Яндекс     Вакансии  Пользователи Пользователи


 Страниц (2): [1] 2 »   

> Без описания
gheka
Отправлено: 24 Апреля, 2015 - 18:29:19
Post Id



Частый гость


Покинул форум
Сообщений всего: 191
Дата рег-ции: Февр. 2011  


Помог: 2 раз(а)




Здравствуйте вопрос такой Имеет ли значение когда запускается функция или нет?

Как правильно?

пример 1
PHP:
скопировать код в буфер обмена
  1.  
  2. function test() {
  3.  
  4. }
  5.  
  6. test ();
  7.  


пример 2
PHP:
скопировать код в буфер обмена
  1.  
  2. test ();
  3.  
  4. function test() {
  5.  
  6. }
  7.  


Или не имеет значение?

Вопрос задан по тому что есть такая проблема у меня есть скрипт и там записан вот похожий код:

PHP:
скопировать код в буфер обмена
  1.  
  2. $t = "SELECT `id` FROM `" . DB_PREFIX . "invoices` WHERE `status`='1' AND `state`='0'";
  3. $result = mysqli_query ( $LinkToBD, sprintf ( $t ));
  4.  
  5. if ( mysqli_num_rows ( $result ) != 0 ) {
  6.        
  7.         while ( $array_result = mysqli_fetch_array ( $result ) ) {
  8.                 $id_invoice = $array_result [0];
  9.                
  10.                  test ($id_invoice);
  11.          }
  12. }
  13.  
  14. function test ($id_invoice = 0) {
  15.  
  16. // Таблица ORDER
  17. $t = "UPDATE `" . DB_PREFIX . "order` SET `money`=mpney+'20' WHERE `id`='$id_invoice'";
  18. $result = mysqli_query ( $LinkToBD, sprintf ( $t ) );
  19.  
  20. // Меняем состояние счёта на 2
  21. $t = "UPDATE `" . DB_PREFIX . "invoices` SET `state`='2' WHERE `id`='$id_invoice'";
  22. $result2 = mysqli_query ( $LinkToBD, sprintf ( $t ) );
  23.  
  24. if ( !$result2 )
  25. die ('Ошибка базы данных ' . mysqli_error ( $LinkToBD ) );
  26.  
  27. }
  28.  
  29.  


Дак вот в примере выше иногда в таблицу ORDER в поле MONEY записывается одна и та же сумму (20+20) хотя должна записаться сумма 1 раз 20

Как проходит счёт с одним ID 2 раза непойму
Ведь после записи в таблицу ORDER состояние счёта меняется на 2 в таблице INVOICES
 
 Top
Sanek_OS9
Отправлено: 24 Апреля, 2015 - 19:03:11
Post Id



Гость


Покинул форум
Сообщений всего: 115
Дата рег-ции: Окт. 2012  
Откуда: Украина


Помог: 0 раз(а)




CODE (SQL):
скопировать код в буфер обмена
  1. $t = "UPDATE `" . DB_PREFIX . "order` SET `money`= `money` + '20' WHERE `id`='$id_invoice' LIMIT 1";
 
 Top
dcc0
Отправлено: 24 Апреля, 2015 - 19:10:34
Post Id


Участник


Покинул форум
Сообщений всего: 1043
Дата рег-ции: Июль 2014  


Помог: 10 раз(а)




Возможно, в старых версиях вызов функии должен был быть в конце, как в bash Улыбка.

Теперь, наверное, все равно.


-----
Март 2021. Бросил программирование
 
 Top
gheka
Отправлено: 24 Апреля, 2015 - 19:11:54
Post Id



Частый гость


Покинул форум
Сообщений всего: 191
Дата рег-ции: Февр. 2011  


Помог: 2 раз(а)




Sanek_OS9 пишет:
$t = "UPDATE `" . DB_PREFIX . "order` SET `money`= `money` + '20' WHERE `id`='$id_invoice' LIMIT 1";


А что даёт LIMIT=1 ведь ID уникальный

Тут идёт речь что функция test () запускается 2 раза, а запустится она может только если состояние счёта равняется 0 STATE=0
(Добавление)
dcc0 пишет:
Возможно, в старых версиях вызов функии должен был быть в конце, как в bash .

Теперь, наверное, все равно.



Скрипт написан под PHP 5.5 и работает на версии 5.5

(Отредактировано автором: 24 Апреля, 2015 - 19:16:45)

 
 Top
Мелкий Супермодератор
Отправлено: 24 Апреля, 2015 - 20:38:02
Post Id



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




gheka пишет:
Имеет ли значение когда запускается функция или нет?

Функции и всё прочее должно быть объявлено до своего использования.
Но PHP в порядке какого-то бреда позволяет делать то, что написано у вас.

Этот код имеет средства контроля параллельного запуска? Иначе говоря, concurrency всегда 1? Почему это не отдано тому, кто написан жить с параллельной работой - СУБД?

gheka пишет:
а запустится она может только если состояние счёта равняется 0 STATE=0

... на момент выполнения 3 строки.


-----
PostgreSQL DBA
 
 Top
dcc0
Отправлено: 24 Апреля, 2015 - 20:51:35
Post Id


Участник


Покинул форум
Сообщений всего: 1043
Дата рег-ции: Июль 2014  


Помог: 10 раз(а)




PHP:
скопировать код в буфер обмена
  1. Функции и всё прочее должно быть объявлено до своего использования.

Круто


-----
Март 2021. Бросил программирование
 
 Top
gheka
Отправлено: 24 Апреля, 2015 - 21:00:08
Post Id



Частый гость


Покинул форум
Сообщений всего: 191
Дата рег-ции: Февр. 2011  


Помог: 2 раз(а)




Мелкий пишет:
Этот код имеет средства контроля параллельного запуска?


Нет наверно если честно я первый раз слышу об этом, можно где то почитать про это?

Мелкий пишет:
Почему это не отдано тому, кто написан жить с параллельной работой - СУБД?


Не понял вопроса, так как написано кто написан жить с параллельной работой - СУБД?

Если вопрос кто создал базу, то я скрипт пишу и базу тоже я создавал.

ID имеет значение PRIMARY KEY

(Отредактировано автором: 24 Апреля, 2015 - 21:05:23)

 
 Top
Мелкий Супермодератор
Отправлено: 24 Апреля, 2015 - 21:51:24
Post Id



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




gheka пишет:
Нет наверно если честно я первый раз слышу об этом, можно где то почитать про это?

В общем случае - предусмотрен ли какой-либо механизм, чтобы этот select мог быть вызван только 1 раз и пока не завершится этот цикл ни один другой поток этот селект обрабатывать не мог?
Читать для СУБД - ACID, транзакции.

Для последующего апдейта лучше хватать сразу эксклюзивную блокировку.
begin;
select /**/ for update;
для каждой строки результата вызываете test
commit;
И rollback если что-то пошло не так вместо commit'а.


-----
PostgreSQL DBA
 
 Top
gheka
Отправлено: 24 Апреля, 2015 - 23:28:47
Post Id



Частый гость


Покинул форум
Сообщений всего: 191
Дата рег-ции: Февр. 2011  


Помог: 2 раз(а)




Мелкий пишет:

В общем случае - предусмотрен ли какой-либо механизм, чтобы этот select мог быть вызван только 1 раз и пока не завершится этот цикл ни один другой поток этот селект обрабатывать не мог?


Не пинайте сильно, нет я не думал что такое может быть

Мелкий пишет:
Читать для СУБД - ACID, транзакции.

Для последующего апдейта лучше хватать сразу эксклюзивную блокировку.
begin;
select /**/ for update;
для каждой строки результата вызываете test
commit;
И rollback если что-то пошло не так вместо commit'а.


Я нашёл что обозначают, и для чего применяются но как именно использовать в запросе это я не нашёл.

COMMIT - успешно завершить транзакцию
ROLLBACK - откатить транзакцию, т.е. вернуть БД в состояние, в котором она находилась на момент начала транзакции.

Напишите пожалуйста как использовать их в запросах. Примеры.

И ПРИМЕР как сделать блокировку чтобы этот SELECT мог быть вызван только 1 раз и пока не завершится этот цикл ни один другой поток этот селект обрабатывать не мог.

(Отредактировано автором: 24 Апреля, 2015 - 23:30:03)

 
 Top
DeepVarvar Супермодератор
Отправлено: 25 Апреля, 2015 - 08:29:43
Post Id



Активный участник


Покинул форум
Сообщений всего: 10377
Дата рег-ции: Дек. 2008  
Откуда: Альфа Центавра


Помог: 353 раз(а)




Мелкий пишет:
Функции и всё прочее должно быть объявлено до своего использования
А вот не совсем так.
Если рассматривать один файл (или несколько "соединенных" в один через requre/include), то нет никакой разницы где мы объявим функции или даже классы с методами.

Происходит примерно так:
1) Чтение файла
2) Парсинг файла
3) Перегонка в опкод
4) Выполнение

Так вот на момент 4-го пункта уже известна область памяти где лежит та или иная функция.
И она просто вызывается.

А вот к порядку объявления переменных порядок важен.
Ибо это уже рантайм (4 пункт).
 
 Top
gheka
Отправлено: 25 Апреля, 2015 - 09:00:43
Post Id



Частый гость


Покинул форум
Сообщений всего: 191
Дата рег-ции: Февр. 2011  


Помог: 2 раз(а)




Спасибо я уже понял что обозначение функции и её запуск не имеет значения в PHP можно запускать функцию как до обозначения её так и после.

Суть моей проблемы как я сейчас понял именно в том что, у меня подобная функция которую я написал в примере в первом сообщении, запускалась из главного файла который прикреплён ко всем фалам моего скрипта. Так как мне необходимо, что бы данная функция запускалась постоянно с заходом нового посетителя на сайт, так как этой функцией обновлялись счета пользователей.

И происходило следующее если в какую ту миллисекунду заходят на сайт 2 посетителя, то функция SELECT на запуск функции срабатывает 2 раза.
И первый цикл не успевает закончится как начинается второй и получается что в базе данных в таблице INVOICES c поле STATE ещё не поменялось на 2 поэтому и получается, что SELECT иногда пропускает 2 раза ID с одним и тем же значением.

По этому я сейчас переделал запуск этой функции в CRON с запуском каждую минуту, там ей и место, почему сразу так не сделал не знаю.
Но у меня есть подобная функция это бронирования товара для покупателя, принцип тот же если одновременно 2 покупателя нажмут кнопку перейти к оплате то проверка на остаток товара может не сработать и получится что 2 покупателя забронируют больше товара чем есть в наличии. По этому без блокировки SELECT тут не обойтись.

Поэтому прошу выложите примеры как блокировать SELECT? на примере процедурного стиля так как я пишу скрипт на нём.

Заранее спасибо.
 
 Top
DeepVarvar Супермодератор
Отправлено: 25 Апреля, 2015 - 09:07:13
Post Id



Активный участник


Покинул форум
Сообщений всего: 10377
Дата рег-ции: Дек. 2008  
Откуда: Альфа Центавра


Помог: 353 раз(а)




gheka пишет:
на примере процедурного стиля

 
 Top
gheka
Отправлено: 25 Апреля, 2015 - 10:28:51
Post Id



Частый гость


Покинул форум
Сообщений всего: 191
Дата рег-ции: Февр. 2011  


Помог: 2 раз(а)




DeepVarvar пишет:
на примере процедурного стиля

PHP:
скопировать код в буфер обмена
mysql_query('START TRANSACTION;');
 
mysql_query('...');
mysql_query('...');
mysql_query('...');
mysql_query('...');
 
mysql_query('COMMIT;');


Спасибо только наверно без ( ; ) mysql_query('START TRANSACTION;');

В моём случае будет так (1)
CODE (PHP):
скопировать код в буфер обмена
  1.  
  2. $t = 'START TRANSACTION';
  3.  
  4. $t = "SELECT `id` FROM `" . DB_PREFIX . "invoices` WHERE `status`='1' AND `state`='0'";
  5. $result = mysqli_query ( $LinkToBD, sprintf ( $t ));
  6.  
  7. if ( mysqli_num_rows ( $result ) != 0 ) {
  8.        
  9.         while ( $array_result = mysqli_fetch_array ( $result ) ) {
  10.                 $id_invoice = $array_result [0];
  11.                
  12.                  test ($id_invoice);
  13.          }
  14. }
  15. $t = 'COMMIT'; 
  16.  
  17. function test ($id_invoices=0) {
  18.  
  19. // Другие SQL запросы
  20.  
  21. }
  22.  
  23.  


Или же так (2)

CODE (PHP):
скопировать код в буфер обмена
  1.  
  2. mysqli_query('START TRANSACTION');
  3.  
  4. $t = "SELECT `id` FROM `" . DB_PREFIX . "invoices` WHERE `status`='1' AND `state`='0'";
  5. $result = mysqli_query ( $LinkToBD, sprintf ( $t ));
  6.  
  7. if ( mysqli_num_rows ( $result ) != 0 ) {
  8.        
  9.         while ( $array_result = mysqli_fetch_array ( $result ) ) {
  10.                 $id_invoice = $array_result [0];
  11.                
  12.                  test ($id_invoice);
  13.          }
  14. }
  15.  
  16. mysqli_query('COMMIT');
  17.  
  18. function test ($id_invoices=0) {
  19.  
  20. // Другие SQL запросы
  21.  
  22. }
  23.  


1 Как правильно на 1 примере или на 2?
2 Я где то читал что транзакции работают только на таблицах InnoDB правда ли это или на MyISAM тоже работает?
 
 Top
Мелкий Супермодератор
Отправлено: 25 Апреля, 2015 - 10:38:55
Post Id



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




gheka пишет:
1 Как правильно на 1 примере или на 2?

Правильно - выкинуть к чертям mysql_* и использовать pdo, у которого реализовано нормальное API по работе с транзакциями.
Ну или хотя бы mysqli. Не столь удобен, но тоже неплох.

gheka пишет:
2 Я где то читал что транзакции работают только на таблицах InnoDB правда ли это или на MyISAM тоже работает?

Только innoDB.
Хранить данные можно только в транзакционном хранилище - это только innoDB и его наследники (XtraDB, и не помню как в mariadb обозвали). Нет транзакционности - нет данных.
(Добавление)
DeepVarvar пишет:
А вот не совсем так.

То что это работает, не означает, что так можно делать.


-----
PostgreSQL DBA
 
 Top
gheka
Отправлено: 25 Апреля, 2015 - 10:50:54
Post Id



Частый гость


Покинул форум
Сообщений всего: 191
Дата рег-ции: Февр. 2011  


Помог: 2 раз(а)




Мелкий пишет:
Ну или хотя бы mysqli. Не столь удобен, но тоже неплох.


Но если вы внимательно смотрели примеры то у меня и написано с использованием mysqli


Мелкий пишет:
Только innoDB.


Значит мне это всё не подходи у меня MyISAM

А переделывать это целая история, так как у меня скрипт в 200-300 файлов

Есть какие либо ещё решения?

(Отредактировано автором: 25 Апреля, 2015 - 10:52:13)

 
 Top
Страниц (2): [1] 2 »
Сейчас эту тему просматривают: 0 (гостей: 0, зарегистрированных: 0)
« Вопросы новичков »


Все гости форума могут просматривать этот раздел.
Только зарегистрированные пользователи могут создавать новые темы в этом разделе.
Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.
 



Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS  RSS

 
Powered by ExBB FM 1.0 RC1. InvisionExBB