If you use this code, please, at the very least, let me know where and how. If you
find it to be useful to you and it saves you time, please consider donating to the
cause. At least send me some coin for beer. (:
JavaScript PHP Remoting Demonstration
Abstraction of PHP class methods into JavaScript. This is a demonstration of a very
fast and easy way to build AJAX-type applications where communications between JavaScript
on the client side and PHP5 on the server side is ideal.
This library makes development of such systems fast and very simple.
Quick answer to a frequently asked question:
Yes, you should cache the JavaScript class created by the PHP. As it stands in these
demo bits of code, the JavaScript class is NOT cached. It is generated every single
time you call it. YES the PHP Reflection API is heavy, which is why you should cache
the JavaScript class output, especially on high traffic pages. During development,
it's a great time saving feature to be able to write or change a PHP method and then
see the effects instantly on your web page.
Quick answer to another frequently asked question:
Yes, this was written to use the Prototype JavaScript library AJAX class functionality.
I've rewritten it to use my own (albeit sloppy) AJAX class and it was pretty painless.
Jump to:
Cutting to the Chase
To make this work for you, all you need is Prototype 1.6 (or better) and my little
PHP class. Get them below here...
The LONG Story
I've been working in Flash and ActionScript for a number of years and the way to
communicate has traditionally been XML. Then I discovered Flash Remoting and AMFPHP, which
is WAY easier to work with. It's a little more work to implement, but once the services
are setup, you can rapidly connect PHP behind the scenes to ActionScript out front. Slick
So, lately, however, I have been building more JavaScript, AJAX-type, PHP systems typically
with MySQL databases behind them all. A good friend of mine wanted a super simple project file
management application for his website where clints would be able to login and see files
relating to their projects. This is by no means a monumental task in PHP/MySQL or in
HTML/JavaScript/CSS. Actually, it's a pretty simple application to build. But, when you
get down to starting something even as simple as this from total scratch, you then realize that
even the little simple pages for managing such a system are a bit tedious and not always a lot
of fun to build.
In particular for me, the communications between the client side and the server side is
always pretty tedious and the JavaScript code tends to be pretty hairy. It isn't that it's
all that complex, but just kinda verbose, ya know? It can turn out to be a lot of code, what with
all the silly AJAX calls and chained AJAX calls and stuff. At least, I think so. Maybe it stems
from my hack-smackery coding? 
What I Thought It Should Be
I had always wanted a way to do Flash Remoting in JavaScript. I believe that I should be able
to write a function in PHP and then call it in JavaScript, passing it parameters like I would in
PHP, and then getting back return values in native JavaScript types. Like this:
PHP Function:
// return a string passed in, but change it before it goes out
public function talkBack( $theySaid = '' ) {
return $theySaid;
}
JavaScript call to PHP function:
myDiv.innerHTML += remoteService.talkBack( "Talk to me, Goose!" );
Output:
Talk to me, Goose!
Is that so much to ask?!
I didn't really search very hard (maybe not at all) for a solution because when I sat
there and thought about it, it didn't seem that difficult to do. I might have been a little
wrong. What I did end up with, though, was pretty small and very functional and very simple. I
thank the programming gods for PHP5 and Reflection API. Can I get a "AMEN!"
So, after an all-nighter of development and testing, here is the product...
How It Works
This one script does two things to make JavaScript to PHP Remoting work. First, it creates
JavaScript code for you based on PHP code you write. Second, it acts as the AJAX service call
responder used to run said PHP code on behalf of the page that is using said JavaScript code.
When you run the script as a JavaScript include in your web page, you pass it the
path portion of the URL that is required to reach the script in making AJAX calls. Example:
<script src="phpService.php?serviceURL=/jsphpremoting" type="text/javascript"></script>
The script creates a bunch of JavaScript code that defines a class that is named after
the script filename itself.
var phpService = {
serviceCall : function () {
// ...
}
// ...
};
So, if you leave the filename of the script as, "phpService.php" after downloading it from my
website, the JavaScript class will be named, "phpService" (see above). You would then be able to
call methods like this:
phpService.methodName( parm1, parm2, callBack );
Methods inside this class are created dynamically (using the Reflection API in PHP5) based
on any public methods you place inside the PHP class at the top of the script. So, if you have a
public method in the PHP class named, "findProductsByCategory," then you will be able to call the
JavaScript method, "phpService.findProductsByCategory()." Example:
Snippet of PHP:
// find products in the $cat category
public function findProductsByCategory
( $cat =
"" ) {
// pretend we have a private variable that is a Database class with a query() method
$this->
db->
query( "SELECT * FROM 'catalog_db`.`product` WHERE `category`='{$cat}'" );
// also pretend that our Database class will tell us if rows were returned
if( $this->
db->
numRows() ) {
// simply return the resulting rows from the query
return $this->
db->
results;
}
// return an empty array (no products found)
return array();
}
Snippet of JavaScript:
// call the remote PHP method to get the products in a category
phpService.findProductsByCategory(
// product category string (first parameter to PHP function)
"Spatulas",
// callback function to deal with return value
function ( r ) {
// the return value is passed into this function
// in this case, an associative array, or database resultset
if( r.length ) {
// there are rows in the result
for( var p = 0; p < r.length; p++ ) {
myDiv.innerHTML += "Item " + ( p + 1 ) + ": " + r[p].title + "<br />";
}
}
}
);
Output would be something like this:
Item 1: RubberMatic™ 76 - Non-stick, flexible and super-sweet!
Item 2: Off-Brand stainless steel, medium size
Item 3: Titanium Broadhead with compass in handle
...
How To Use JavaScript to PHP Remoting
Just build your page, include the script in a script tag and pass it the location where it
sits in your URL structure using the serviceURL GET parameter, write your PHP methods, write
your JavaScript, and sit back and giggle at how easy it is.
Here is code for a sample page that includes the PHP script and makes it create the JavaScript
class that you will ultimately use for making remote method calls:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
<head>
<title>Example 1 - XHTML 1.0 Strict as text/html
</title>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<script src="phpService.php?serviceURL=/jsphpremoting" type="text/javascript"></script>
</head>
<body>
<h1>Example of JavaScript calling remote PHP methods
</h1>
<p>
Type in something to say to yourself, then click the "Echo It" button.
</p>
<p>
<code id="returnSaid">This will be where the return shows up...
</code>
</p>
<p>
What to say:
<br />
<input type="text" id="txtSay" value="" />
</p>
<p>
<input type="button" id="btnEcho" value="Echo It" onclick="sendEcho()" />
</p>
<script type="text/javascript">
//
<![CDATA[
function outputEcho( returnVal ) {
$('returnSaid').innerHTML = returnVal;
}
function sendEcho() {
phpService.echoBack( $('txtSay').value, outputEcho );
}
// ]]>
</script>
</body>
</html>
More importantly, here is the snippet of JavaScript from that page that does the call and
changes the innerHTML of the "returnSaid" element:
function outputEcho( returnVal ) {
$('returnSaid').innerHTML = returnVal;
}
function sendEcho() {
phpService.echoBack( $('txtSay').value, outputEcho );
}
Here is how I would write it to save space and eliminate what I concsider to be unnecessary
functions (use anonymous functions where you can, unless it will make your code horribly
unreadable):
function sendEcho() {
phpService.echoBack(
$('txtSay').value,
function ( returnVal ) {
$('returnSaid').innerHTML = returnVal;
}
);
}
Here is the snippet of code for the phpService.php script that makes this page go zoom:
class RemoteMethods extends JavaScriptPHPRemoteMethods {
// return a string passed in from JavaScript
public function echoBack( $theySaid = '' ) {
return $theySaid;
}
}
// more internal stuff below here left out for the sake of example here
// ...
Test Calls and Returns
I threw this in here at the bottom to show the various return types and as a good way for you
to cut-n-paste examples of various method calls and return types.
PHP code for test phpService.php script:
<?php
class RemoteMethods
extends JavaScriptPHPRemoteMethods
{
//
// Use private methods for utility in your public JS-visible methods
//
private $myPrivateVar;
private function setupPrivateVar
( $addOn =
"" ) {
$this->
myPrivateVar =
"This is private. " .
$addOn;
}
//
// JavaScript-visible methods (put your methods here)
//
// return a simple array
public function getArray
() {
return array( "One",
"Two",
"Three" );
}
// return a string passed in
public function echoBack
( $theySaid =
'' ) {
return $theySaid;
}
// return a string passed in, but change it before it goes out
public function echoBackWithChange
( $theySaid =
'' ) {
$weSaid =
"You told me, \"{$theySaid}\" and I say, \"Fooey!\"";
return $weSaid;
}
// just add some numbers together and return the result
public function addThreeNumbers
( $a =
0,
$b =
0,
$c =
0 ) {
return $a +
$b +
$c;
}
// setup and then return a private variable
public function getPrivateVar
() {
$this->
setupPrivateVar( "So do not say anything!" );
return $this->
myPrivateVar;
}
// return an associative array (JS will see an object)
public function getAnAssociative
() {
return array(
"id" =>
17,
"name" =>
"Bob",
"state" =>
"Arizona",
"alive" =>
true,
"kids" =>
array( "Sam",
"Sue",
"Sally" )
);
}
// return a property of an object that was passed in from JS
// note: this also demonstrates how exceptions are thrown cross-language
public function showProperty
( $obj,
$propName =
"" ) {
if( empty( $propName ) ) {
throw
new Exception
( "Please give me a property name." );
}
if( !
isset( $obj->
$propName ) ) {
throw
new Exception
( "Object has no property by the name of '{$propName}'." );
}
return $obj->
$propName;
}
} // end of remote methods class
//
// There is more below here in the full PHP script, but it is eliminated here because it isn't necessary
// for this test/demonstration. -af
//
?>
JavaScript code on this page that outputs test values below:
function trace( msg ) {
$("trace").innerHTML += msg + "<br />\n";
}
phpService.getArray(
function ( r ) {
trace( "<strong>getArray()</strong>" );
for( var i = 0; i < r.length; i++ ) {
trace( "r[" + i + "] = " + r[i] );
}
trace( "<br />" );
}
);
// return a string passed in
phpService.echoBack(
"Hi from JavaScript",
function ( r ) {
trace( "<strong>echoBack()</strong>" );
trace( r + "<br />" );
}
);
// return a string passed in, but change it before it goes out
phpService.echoBackWithChange(
"Hi from JavaScript",
function ( r ) {
trace( "<strong>echoBackWithChange()</strong>" );
trace( r + "<br />" );
}
);
// just add some numbers together and return the result
phpService.addThreeNumbers(
function ( r ) {
trace( "<strong>addThreeNumbers()</strong>" );
trace( r + "<br />" );
}
);
// setup and then return a private variable
phpService.getPrivateVar(
function ( r ) {
trace( "<strong>getPrivateVar()</strong>" );
trace( r + "<br />" );
}
);
// return an associative array (JS will see an object)
phpService.getAnAssociative(
function ( r ) {
trace( "<strong>getAnAssociative()</strong>" );
trace( "id: " + r.id );
trace( "name: " + r.name );
trace( "state: " + r.state );
trace( "alive: " + ( r.alive ? "Yes" : "No" ) );
for( var k = 0; k < r.kids.length; k++ ) {
trace( "kid #" + k + ": " + r.kids[k] );
}
trace( "<br />" );
}
);
// return a property of an object that was passed in from JS
// note: this also demonstrates how exceptions are thrown cross-language
var now = new Date();
var transaction = { id: 184736, started: now, amount: 12.75 };
phpService.showProperty(
transaction, "amount",
function ( r ) {
trace( "<strong>showProperty()</strong>" );
trace( "transaction.amount is " + r + "<br />" );
}
);
Output from test method calls (LIVE! This is written by actual JavaScript as the page loads!):