Удивишись, что мой хабраюмор хабралюди понимают с трудом, перешел к написанию ещё одного интересного хабратопика. :)
Хочу предложить один удобный метод для взаимодействия Javascript с PHP.
Можно в PHP добавить класс, с возможность 'удаленного' запуска оттуда функций с параметрами.
Наиболее подходящий способ — с помощью массива.
Как передать массив? Самый простой и наиболее оптимальный метод (учитывая, что мы имеем дело с Javascript) — это JSON. Передача параметров на запуск будет выглядеть, например:
Класс имеет следующие функции:
— $this->add({название метода},{функциия}) позволяет добавляет новый метод. Если метод существует, добавляет в него ещё одну функцию.
— $this->{название метода}({параметры}) идёт вызов всех добавленных функций в методе.
— $this->run({массив}) запускает последовательно на выполнение несколько методов, используя параметры из массива.
Сразу сделаю ремарочку для непрофессионалов:
равносильно
Пример:
Необходимо создать интерфейс работы с БД с получением информации.
Для начала инициализируем интерфейс, которым будем пользоваться:
Метод run позволяет запускать несколько групп с разными переметрами последовательно. Принимает названия групп он в виде массива:
Вы наверное заметили, что db::load возвращает результаты в виде массива. Эти результаты инкапсулируются(добавляются) или простыми словами попадают в общий массив $this->result. В результате, мы будем использовать этот массив, как ответ JavaScript'у на запрос.
Тоесть, например, запустив loaddb(200) и loaddb(300) — мы получим на выходе массив, имеющий заполненные поля: 'DBresult'=>('200'=>… и '300'=>...).
Ну а теперь самое главное — это реализвация декодирования (на вход) и кодирования (на выход) JSON массивов в PHP, с запуском вызываеммых с помощью Javascript методов:
server_eval посылает запрос в UserInterface файла JSON.php и при получении ответа, запускает функцию time_result, передавая ответ в параметрах. При этом можно осуществлять совершенно различные запросы в интерфесе и обрабатывать результаты, как душе будет угодно.
На данной стадии реализации у меня была проблемма — сделать универсальную библиотеку, в которой возможно изменение-добавление новых функций несколькими разработчиками.
Примеры:
1) Опять вернусь к разработке космической игры.
Игрок выбрал кораблю другую цель. Идёт передача выбора цели. «ship_new_target(180,320);return_space_objects(1220,1334);». 180- корабль, а 320- новая цель.
Новая цель может оказаться чем угодно. В случае, если это корабль, нам необходимо будет выделить её как врага. Если это станция, мы выделим её как станцию и автоматически пошлём корабль лететь на неё. Если это планета, тогда мы её выделять вообще не будем.
При этом мы можем добавить любой новый тип объекта не меняя кода, а просто добавив необходимые вызовы и как на них необходимо реагировать, когда в них будет необходимость.
Кстати говоря, функция ship_new_target ничего не возвращает. А вот функция return_space_objects занимается тем, что создаёт в общем массиве массив объектов, лежащих рядом с координатами (1220,1334). При этом — опять-же, обрабатываются, например порталы и добавляются в массив (используя некоторые правила). Затем, корабли, станции, вызывая последовательно функции метода return_space_objects и добавляя результаты DB-выборок в общий массив.
Таким образом мне проще общаться со всеми объектами и код у меня не разбросан по php-файлам, а лежит каждый участок в своём месте.
2) Форум.
Простой пример — У каждого поста есть свой ID. У каждой темы тоже есть свой ID. Они не пересекаются.
При любом ответе, вызывается функции 'add_reply(12345,«comment»);return_topic(12345);'.
В add_reply имеется несколько функций — функция добавление к топику, функция добавления к комментарию.
Если ID (12345), к которому прикрепляется сообщение, является новым топиком- тогда мы используем одну функцию, добавляя это сообщение, как топик. Если ID является комментарием пользователя, тогда мы используем совсем другую функцию, которая прикрепляет комментарий к нему.
Затем, простым добавлением библиотеки, можно сделать добавление комментариев в чём угодно, например к картинкам, к личным сообщениям (если друг имеет ID, который не пересекается с другими топиками, комментариями) итд.
Метод return_topic тоже работает так-же. Если ID топика, тогда мы возвращаем топик с комментариями. Если это ID комментария — то только комментарий с его вложениями. Тоже самое можно сделать и для использования картинок, музыки и всего, чего душе угодно.
Возврат ошибок, кстати, тоже возможен — используя, например 'ERROR', в который просто добавлять ошибки. При нескольких ошибках он будет выглядеть примерно так:
{«ERROR»:[«Не достаточно знаков»,«Не присутствует заголовок», итд]}.
Хочу предложить один удобный метод для взаимодействия Javascript с PHP.
Можно в PHP добавить класс, с возможность 'удаленного' запуска оттуда функций с параметрами.
Передача параметров
Каким образом лучше всего передать функции на вход PHP?Наиболее подходящий способ — с помощью массива.
Как передать массив? Самый простой и наиболее оптимальный метод (учитывая, что мы имеем дело с Javascript) — это JSON. Передача параметров на запуск будет выглядеть, например:
{Преобразовать это в массив на стороне PHP можно очень просто — с помощью json_decode. Осталось только разобрать полученный массив по полочкам, а полученный результат вывести обратно в виде JSON клиенту.
«init_timer»:[],
«savedb»:[200],
«check_timer»:[]
}
что соответствует:
init_timer();
savedb(200);
check_timer();
User Interface
Реализовал я это с помощью PHP-класса UserInterface.class UserInterface{В этот класс мы будем добавлять новые методы (функции), а затем с помощью небольшой доработки, научим Javascript «видеть» и запускать их, получая результаты их работы.
private $if;
public $result=array();
function add($groupname,$if){
$this->if[$groupname][]=$if;
}
function __call($name, $args){
if (isset($this->if[$name]))
foreach ($this->if[$name] as $func)
!is_array($res=&call_user_func_array($func,$args)) ||
$this->result=array_merge_recursive($this->result,$res);
}
function run($info){
if (is_array($info))
foreach ($info as $func=>$parameters)
!is_array($res=&call_user_func_array(array(&$this, $func),$parameters)) ||
$this->result=array_merge_recursive($this->result,$res);
}
}* This source code was highlighted with Source Code Highlighter.
Класс имеет следующие функции:
— $this->add({название метода},{функциия}) позволяет добавляет новый метод. Если метод существует, добавляет в него ещё одну функцию.
— $this->{название метода}({параметры}) идёт вызов всех добавленных функций в методе.
— $this->run({массив}) запускает последовательно на выполнение несколько методов, используя параметры из массива.
Сразу сделаю ремарочку для непрофессионалов:
!is_array($res=&call_user_func_array($func,$args)) || $result=array_merge_recursive($result,$res);
равносильно
$res=&call_user_func_array($func,$args);
if(is_array($res))
$result=array_merge_recursive($result,$res);
Пример:
Необходимо создать интерфейс работы с БД с получением информации.
Для начала инициализируем интерфейс, которым будем пользоваться:
$UImethod = new UserInterface();Добавляем группу, которая должна добавлять информацию в БД (savedb):
class db{Запуск будет осуществляться с помощью функции:
static function save($num){
//Функция для записи в БД
//$num->...
}
static function load($num){
//Функция для загрузки из БД
//$db<-...
return array(«DBresult»=>$db);
}
}
$UImethod->add('savedb','db::save');
$UImethod->add('loaddb','db::load');
$UImethod->savedb($xxx);При этом, если вдруг нам потребуется добавить модуль создания логов, то обработку можно легко добавить в эту же группу:
class log{Теперь будет происходить последовательный запуск обеих функций, при запуске группы 'savedb'.
static function add_savelog($num){
//Добавить новый лог
//...
}
}
$UImethod->add('savedb','log::add_savelog');
Работа Javascript c классом UserInterface
Сначала хочу немного остановиться на методе run. Это нам поможет в заимодействии.Метод run позволяет запускать несколько групп с разными переметрами последовательно. Принимает названия групп он в виде массива:
$a=array(Тогда, запустив $UImethod->run($a); можно сохранить в базу данных — 200, затем её считать с помощью 'loaddb'.
«savedb»=>array(200)
«loaddb»=>array(200)
)
Вы наверное заметили, что db::load возвращает результаты в виде массива. Эти результаты инкапсулируются(добавляются) или простыми словами попадают в общий массив $this->result. В результате, мы будем использовать этот массив, как ответ JavaScript'у на запрос.
Тоесть, например, запустив loaddb(200) и loaddb(300) — мы получим на выходе массив, имеющий заполненные поля: 'DBresult'=>('200'=>… и '300'=>...).
Ну а теперь самое главное — это реализвация декодирования (на вход) и кодирования (на выход) JSON массивов в PHP, с запуском вызываеммых с помощью Javascript методов:
if (!isset($_REQUEST['method']))
die();
$functions=json_decode($_REQUEST['method'],TRUE);
$UImethod->run($functions);
echo json_encode($UImethod->result);
Запуск методов из JavaScript
Добрались до сладкого.<html><head></head><body>Собственно и всё.
<script type=«text/javascript»>
//Функция, реализующая AJAX запрос на сервер
//Параметры URL, JS-функция, дополнительные параметры, [следующий URL, JS-func...]
function ajax_load(url,parcer,par,next){
var req, ab, done=0;
this.request=function(){
if (window.XMLHttpRequest)
ajaxRequest = new XMLHttpRequest();
else if (window.ActiveXObject){
ajaxRequest = new ActiveXObject(«Msxml2.XMLHTTP»);
if (!ajaxRequest)
ajaxRequest = new ActiveXObject(«Microsoft.XMLHTTP»);
}
return ajaxRequest;
}
this.ReqStatus=function() {
if (req.readyState == 4) {
clearTimeout(ab);
if (req.status == 200){
parcer(req,par);
if (next)
ajax_load(next[0],next[1],next[2],next[3]);
} else
alert(«AJAX Error: \n» + req.statusText + "\n" + url);
}
}
if (!url)
return parcer(par);
req=this.request();
req.onreadystatechange = this.ReqStatus;
req.open(«GET», url, true);
req.send(null);
ab = window.setTimeout(function(){req.abort();}, 10000);
return req;
}
//Функция, которая кодирует запрос в JSON формат (func(param) -> «func»:[param]) и отсылает его на сервер (делая запрос «JSON.php?method=...»)
function server_eval(mod,ret){
mod=mod.replace(/\s*([\w\d_]+)\s*\(([\w\d_. \\,\[\]"]*)\)\s*;?/gi,'"$1":[$2],').replace("'",'"');
mod='{'+mod.substr(0,mod.length-1)+'}';
ajax_load("JSON.php?method="+mod,ret,null);
}
//Обработчик запроса
function time_result(res){
db=eval('(' + res.responseText + ')');
document.write(db['DBresult']);
}
//Запрос на сервер с обработчиком ответа time_result
server_eval('savedb(200);loaddb(200);loaddb(300);',time_result);
</script>
</body></html>* This source code was highlighted with Source Code Highlighter.
server_eval посылает запрос в UserInterface файла JSON.php и при получении ответа, запускает функцию time_result, передавая ответ в параметрах. При этом можно осуществлять совершенно различные запросы в интерфесе и обрабатывать результаты, как душе будет угодно.
Для чего это можно использовать
На данной стадии реализации у меня была проблемма — сделать универсальную библиотеку, в которой возможно изменение-добавление новых функций несколькими разработчиками.
Примеры:
1) Опять вернусь к разработке космической игры.
Игрок выбрал кораблю другую цель. Идёт передача выбора цели. «ship_new_target(180,320);return_space_objects(1220,1334);». 180- корабль, а 320- новая цель.
Новая цель может оказаться чем угодно. В случае, если это корабль, нам необходимо будет выделить её как врага. Если это станция, мы выделим её как станцию и автоматически пошлём корабль лететь на неё. Если это планета, тогда мы её выделять вообще не будем.
При этом мы можем добавить любой новый тип объекта не меняя кода, а просто добавив необходимые вызовы и как на них необходимо реагировать, когда в них будет необходимость.
Кстати говоря, функция ship_new_target ничего не возвращает. А вот функция return_space_objects занимается тем, что создаёт в общем массиве массив объектов, лежащих рядом с координатами (1220,1334). При этом — опять-же, обрабатываются, например порталы и добавляются в массив (используя некоторые правила). Затем, корабли, станции, вызывая последовательно функции метода return_space_objects и добавляя результаты DB-выборок в общий массив.
Таким образом мне проще общаться со всеми объектами и код у меня не разбросан по php-файлам, а лежит каждый участок в своём месте.
2) Форум.
Простой пример — У каждого поста есть свой ID. У каждой темы тоже есть свой ID. Они не пересекаются.
При любом ответе, вызывается функции 'add_reply(12345,«comment»);return_topic(12345);'.
В add_reply имеется несколько функций — функция добавление к топику, функция добавления к комментарию.
Если ID (12345), к которому прикрепляется сообщение, является новым топиком- тогда мы используем одну функцию, добавляя это сообщение, как топик. Если ID является комментарием пользователя, тогда мы используем совсем другую функцию, которая прикрепляет комментарий к нему.
Затем, простым добавлением библиотеки, можно сделать добавление комментариев в чём угодно, например к картинкам, к личным сообщениям (если друг имеет ID, который не пересекается с другими топиками, комментариями) итд.
Метод return_topic тоже работает так-же. Если ID топика, тогда мы возвращаем топик с комментариями. Если это ID комментария — то только комментарий с его вложениями. Тоже самое можно сделать и для использования картинок, музыки и всего, чего душе угодно.
Возврат ошибок, кстати, тоже возможен — используя, например 'ERROR', в который просто добавлять ошибки. При нескольких ошибках он будет выглядеть примерно так:
{«ERROR»:[«Не достаточно знаков»,«Не присутствует заголовок», итд]}.