Для одного из следующих докладов реализовал .mRPC — простой механизм вызова серверных методов со стороны клиента.
Рабочий пример.
Заранее прошу прощения за ужасную разметку на Хабре, корректная статья находится в моём персональном блоге...
Да, дополню — аргументы и возвращаемое значение серверной функции не лимитированы ничем, кроме ограничений сериализации как таковой. Хотите вернуть с сервера массив или хэш любой вложенности — Вас никто не ограничивает ;)
Вот так это выглядит на клиенте:
А вот так мы описываем классы на сервере (config.php, код для Perl будет позднее, но его легко написать и самому, с помощью CPAN Class::Inspector):
Исходный текст класса MRpc (MRpc.class.php):
И, наконец, код index.php (диспетчер):
Рабочий пример.
Заранее прошу прощения за ужасную разметку на Хабре, корректная статья находится в моём персональном блоге...
Да, дополню — аргументы и возвращаемое значение серверной функции не лимитированы ничем, кроме ограничений сериализации как таковой. Хотите вернуть с сервера массив или хэш любой вложенности — Вас никто не ограничивает ;)
Вот так это выглядит на клиенте:
- <!-- jQuery -->
- <script type=«text/javascript» src="/samples/mrpc/jquery.js"></script>
- <!-- JSON-serialization support -->
- <script type=«text/javascript» src="/samples/mrpc/jquery.json.js"></script>
- <!-- .mrpc support -->
- <script type=«text/javascript» src="/samples/mrpc/jquery.mrpc.js"></script>
- <!-- description of supported server classes and methods -->
- <script type=«text/javascript» src="/samples/mrpc/"></script>
- <!-- А здесь вызываем метод yo класса Test в синхронном режиме -->
- <a href=«javascript:;» onclick=«alert($.mrpc.Test.yo('foo'))»>foo</a>
А вот так мы описываем классы на сервере (config.php, код для Perl будет позднее, но его легко написать и самому, с помощью CPAN Class::Inspector):
class Test
{
public static function yo($s)
{
return 'ok, I got parameter "'. addslashes($s). '"';
}
}
MRpc::registerRpcClass('Test');
Исходный текст класса MRpc (MRpc.class.php):
class MRpc
{
private static $classes = array();
public static function registerRpcClass($className)
{
MRpc::$classes[] = $className;
}
public static function getClassNames()
{
return MRpc::$classes;
}
public static function getClassMethodNames($className)
{
if (!class_exists($className))
{
require_once($className. '.class.php');
}
return get_class_methods($className);
}
public static function performCall($className, $methodName, $arguments)
{
if (!in_array($className, MRpc::$classes))
{
header('HTTP/1.1 404 Not Found');
header('Status: 404 Not Found');
print '{status: false, class: "Not registered"}';
exit;
}
$methodNames = MRpc::getClassMethodNames($className);
if (!in_array($methodName, $methodNames))
{
header('HTTP/1.1 404 Not Found');
header('Status: 404 Not Found');
print '{status: false, method: "Not registered"}';
exit;
}
return call_user_func_array(array($className, $methodName), $arguments);
}
}
И, наконец, код index.php (диспетчер):
require_once(dirname(__FILE__). '/MRpc.class.php');
require_once(dirname(__FILE__). '/config.php');
header('Content-type: text/plain');
if (array_key_exists('class', $_REQUEST) && array_key_exists('method', $_REQUEST) && array_key_exists('arguments', $_REQUEST))
{
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past
print json_encode(MRpc::performCall($_REQUEST['class'], $_REQUEST['method'], json_decode($_REQUEST['arguments'])));
exit;
}
$classes = array();
foreach (MRpc::getClassNames() as $className)
{
$def = array('name' => $className, 'url' => $_SERVER['PHP_SELF'], 'methods' => array());
foreach (MRpc::getClassMethodNames($className) as $methodName)
{
$def['methods'][] = $methodName;
}
$classes[] = $def;
}
?>
// JavaScript code - MRPC wrapper
(function($)
{
$.mrpc( ?php print json_encode($classes); ? );
})(jQuery);
