用PHP for Microsoft AJAX Library增强PHP编程

来源:岁月联盟 编辑:zhuzhu 时间:2009-07-02

  一、引言

  众所周知,ASP.NET AJAX框架由三个子框架组成:ASP.NET 2.0 AJAX Extensions,ASP.NET AJAX Control Toolkit以及ASP.NET Futures CTP。其中,前二者极大地依赖于ASP.NET 2.0服务器端技术。实际上,这两部分的主要设计目的正是在于扩展ASP.NET 2.0(及以后版本)程序的Ajax特征。对比之下,ASP.NET Futures CTP(之前的代码称为“ASP.NET AJAX Futures CTP”)与ASP.NET服务器端的耦合性非常小,但也主要是服务于ASP.NET程序的开发,只是由于这时的主要业务逻辑由服务器转移到了客户端,从而能够极大地改善客户端用户体验并进而提高系统的整体性能。

  但是,另一方面,我们也应该看到上述三个部分中都提供了大量现成的JavaScript源码,其中大部分集中在ASP.NET 2.0 AJAX Extensions和ASP.NET Futures CTP。最重要的是,其中绝大部分的JavaScript代码完全可以轻易地分离出来并进一步应用于其他类型的web开发平台上。这些JavaScript源码库主要包括MicrosoftAjax.js,MicrosoftAjaxTimer.js和MicrosoftAjaxWebForms.js,还有ASP.NET Futures CTP中的PreviewScript.js,PreviewGlitz.js和PreviewDragDrop.js等。通过进一步分析来看,我们可以轻易发现其实它们都是一些独立的JavaScript代码,仅仅是其相应的一个副本以嵌入式资源方式存在于程序集System.Web.Extensions.dll及Microsoft.Web.Preview.dll中罢了。也就是说,它们中的绝大部分是独立于ASP.NET服务器端的。因此,我们完全有可能把这些脚本移植到其他服务器端web开发平台上,例如JSP,PHP及Perl等。于是,在基于这些服务器平台开发web应用的过程中,我们可以尽情地应用ASP.NET AJAX框架的客户端技术,其中包括大量的ASP.NET AJAX脚本特征,甚至是更高级的ASP.NET AJAX客户端框架编程技巧。

  然而,我们也应该清醒地认识到,要成功实现ASP.NET AJAX框架功能,特别是ASP.NET AJAX服务器控件ScriptManager及UpdatePanel控件等所具备的强大功能还有待于利用其他的非ASP.NET技术作深入的模仿性开发。

  在本文中,我们主要想探讨如何利用开源工程PHP for Microsoft AJAX Library把ASP.NET AJAX客户端框架所提供的简易的Web服务技术引入到PHP Web开发环境下。尽管目前的开源工程PHP for Microsoft AJAX Library还未真正成熟起来,但是我们可以早一步领略如何在PHP平台上引入Microsoft AJAX Library并为其增加流行的Ajax特征。

  二、开源工程PHP for Microsoft AJAX Library简介

  2007年1月,微软的Steve Marx在网站Codeplex(http://www.codeplex.com/phpmsajax)上发布了一个开源工程。他试图把微软ASP.NET AJAX框架中的Microsoft AJAX Library引入到PHP开发领域。

  下面,让我们简单地分析一下工程PHP for Microsoft AJAX Library的实现原理。

  到目前为止,工程PHP for Microsoft AJAX Library中仅包含了两个PHP文件:MSAjaxProxyGenerator.php和MSAjaxService.php。其中,在文件MSAjaxService.php中定义了一个PHP类MSAjaxService。我们可以由这个类进一步派生自己的定制类以便使用PHP编程模拟实现Web服务并实现相应的Web方法定义。在另一个文件MSAjaxProxyGenerator.php中定义了另一个PHP类MSAjaxProxyGenerator,通过这个类的generateClientProxy()方法并借助于Microsoft AJAX Library便可以轻松实现生成Web服务的客户端JavaScript代理。

  在正式分析本文示例之前,还是让我们先来了解一下本实验所需要的测试环境及有关安装。

  三、下载与安装PHP for Microsoft AJAX Library

  打开浏览器并导航到网址http://www.codeplex.com/phpmsajax。此网址上提供了有关这个工程的所有相关信息。注意到,目前这个工程的最新版本为3 Alpha。当点击页面中的超级链接“3 Alpha”,你会被导航到另一个页面http://www.codeplex.com/phpmsajax/Release/ProjectReleases.aspx?ReleaseId=1692。图1给出了此页面中与下载工程相关的片断快照。

用PHP for Microsoft AJAX Library增强PHP编程

  图1 下载开源工程PHP for Microsoft AJAX Library

  从图1可见,有两个下载选项:文件phpmsajax.zip或文件phpmsajax-NoSource.zip。在此建议下载前者,因为其中还提供了两个简单的工程应用示例。但是,请不必对这两个示例抱有过大的希望,因此它们都是入门级的。

  四、下载与安装PHP及Web服务器

  根据前面PHP for Microsoft AJAX Library工程主页的介绍,要使用这个工程至少需要PHP 5.2或以上版本,而且必须安装php-json模块。另外,这个主页上也提供了php-json模块的下载地址http://www.aurore.net/projects/php-json/。此主页上还提示Steve已经在IIS7(Vista)以及Apache(Ubuntu 6.06+PHP5.2)两种Web服务器环境下对此工程进行过测试。

  值得庆幸的是,由于近几年PHP及Apache Web服务器发展迅猛,最近各自已经推出了相当稳定的正式发行版本:PHP 5.25和Apache 2.28。因此,你只需要根据自己的操作系统平台的具体情况下载这两个工具并进行相应的安装试验,一切应该没有多大问题。

  由于本人使用的软件环境为Windows XP专业版+Visual Studio 2005+ASP.NET AJAX框架+IIS 5.1(Windows XP内置)。所以,我首先想到在IIS 5.1服务器上测试PHP for Microsoft AJAX Library工程。遗憾的是,我先后下载并多次安装试用了PHP 5.20、PHP 5.23和PHP 5.25,但在IIS 5.1服务器上测试工程自带的示例(还下载了网上极有限的其他几个示例)时都出现了相当类似的错误提示,如图2所示。

用PHP for Microsoft AJAX Library增强PHP编程

  图2 在IIS 5.1服务器上测试工程自带示例出现错误  

  目前,我基本推断是IIS 5.1服务器“作的怪”,很可能是因为IIS的版本太低导致了如图2所示的错误(因时间关系,请恕不能在更高的IIS版本上测试,有条件或有兴趣的读者可以自行试验我的上述推断)。

  无奈之余,我下载并安装了Apache 2.2.6,一切调试居然顺利通过。

  值得注意的是,安装PHP 5.20版本时还需要另行下载相应版本的php-json模块,因为这个工程中要使用JSON技术实现数据在浏览器端与PHP服务器端的数据格式的转换。但是,由于PHP 5.23和PHP 5.25版本都内置了对于JSON技术的支持(不再以独立的扩展模块文件的形式存在),所以使用这两个版本更好一些。

  另外,对于PHP初学者,本人强烈推荐下载使用PHPnow-1.4.4(http://www.phpnow.org/download.html)一键式工程。PHPnow是Win32下绿色免费的Apache+PHP+MySQL环境套件包,最新版本中包含了Apache-2.2.8、PHP-5.2.5、MySQL-5.0.51a、Zend Optimizer-3.3.0、phpMyAdmin-2.11.4和eAccelerator0952_5.2.5。下载文件为PHPnow-1.4.4.exe,大小约为15,361KB。双击这个文件后,只需要几个简单的确定或回车,一切由这个系统自动测试安装环境并进行优化安装。这个框架所附带PnCp.cmd控制面板能够帮助你快速配置你的套件,使用非常方便。安装PHPnow只需解压、初始化,就可得到一个标准的Apache+PHP+MySQL的服务器开发环境。

  下面,我们来讨论下载Microsoft AJAX Library的问题。

  五、下载Microsoft AJAX Library

  这一步是相当容易的,其下载地址为http://www.asp.net/ajax/downloads/,图3给出了这个下载页面的截图。

用PHP for Microsoft AJAX Library增强PHP编程

  图3 下载Microsoft AJAX Library  

  实际上,在下载后你会发现这个库中的几个脚本与ASP.NET AJAX框架的ASP.NET 2.0 AJAX Extensions部分所附带的.js源码基本是一致的,只不过是多了同一个脚本文件的几个语言版本罢了。

  现在,一切准备就绪,让我们着手开发一个利用PHP for Microsoft AJAX Library为PHP网站添加Ajax特性的实例。其中的示例页面将实现通过模拟的Web服务从PHP服务器端以异步方式检索动物信息。

  六、使用PHP类定义Web服务

  首先,我们应该定义一个典型的PHP类Animal。这个类充当服务器端数据的面向对象包装器。注意,为了简化起见,在本例中我们没有把数据存储在数据库(典型情况下是利用MySQL)中。下面给出这个Animal类的相应定义:

   class Animal
{
    //定义一个静态数组存储数据
    static $data = array();
      public $Name;
      public $Category;
      public $Color;
    //构造函数
    public function __construct()
    {
        @list(
            $this->Name,
            $this->Category,
            $this->Color) = func_get_args();
    }
    //返回动物信息的主要方法
    public function GetAllAnimals()
    {
        if (count(Animal::$data) == 0)
        {
            //以硬编码方式把数据存储到数组中
            Animal::$data[] = new Animal("Felix", "Cat", "Grey");
            Animal::$data[] = new Animal("Fido", "Dog", "Brown");
            Animal::$data[] = new Animal("Rover", "Dog", "Brown");
            Animal::$data[] = new Animal("Daisy", "Cow", "Black and White");
            Animal::$data[] = new Animal("Polly", "Parrot", "Green");
        }
        return Animal::$data;
    }
}

  既然上面的PHP类相对简单而且我们的主要兴趣点也不在于此,那么,我们接下来把重点放到使用PHP技术模仿实现的Web服务类的解析上。

  在本例中定义的Web服务类是AnimalService,其完整源码如下所示:

   <?php
require_once 'MSAjaxService.php';
require_once 'Animal.php';
class AnimalService extends MSAjaxService
{
    function GetAllAnimals()
    {
        return Animal::GetAllAnimals();
    }
}
$service = new AnimalService();
$service->ProcessRequest(array('Animal') );
?>

  在此,我们首先需要引用文件MSAjaxService.php。此文件中定义了PHP类MSAjaxService,此类又进一步调用PHP类MSAjaxProxyGenerator,最终实现在客户端生成Web服务代理。

  接下来,我们从类MSAjaxService派生出定制类AnimalService。为了简化问题,在此仅定义了一个web方法GetAllAnimals()。GetAllAnimals()方法又进一步调用类Animal的方法GetAllAnimals(),最后由该方法返回一个Animal对象的数组。

  最后,我们创建了Web服务AnimalService的一个实例,并把它存放到变量$service中。然后调用此实例的ProcessRequest()方法,同时把array('Animal')作为参数传递过去。至此,所有服务器端工作执行完毕。

  读者可能已经猜出,所有的秘密正在MSAjaxService类的ProcessRequest()方法上。不错,这个方法的确负责好几项任务:生成客户端代理,调用方法json_decode()对来自于客户端的数据进行解码,调用方法json_encode()以json方式对初始数据进行编码以便传递到客户端,等等。

  下面,我们来看一下客户端HTML页面的设计以及调用PHP Web服务的实现逻辑。

  七、编写调用PHP Web服务的HTML页面

  在构建好前面的Web服务后,现在我们来编写一个Web页面(可以是.php,.htm或.html文件,在此我们选择.html格式)以便调用前面的Web服务。本示例页面为index.html。为了方便讨论,我们干脆列出所有相关源码。

   <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
 <title>ASP.NET AJAX On PHP Demo</title>
 <link href="site.css" rel="stylesheet" type="text/css" />
 <script type="text/javascript" src="MicrosoftAjax.js"></script>
 <script type="text/javascript" src="PreviewScript.debug.js"></script>
    <script type="text/javascript" src="AnimalService.php/js"></script>
</head>
<body>
      <div id="Contents">
        <div>
          <input type="button" onclick="GetAnimals()" value="Get Animals" />
        </div>
        <!-- Visual templates for ListView control-->
        <div id="Results">
          <div style="display:none;">
            <div id="Results_layout">
              <div id="Results_layout_parent">
                <div id="Result_item" class="resultItem">
                  <span id="Result_Name" class="Result_Name"></span>
                  <span id="Result_Category" class="Result_Category"> </span>
                  <span id="Result_Color" class="Result_Color"></span>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
  <script type="text/javascript">
      function GetAnimals()
      {
          AnimalService.GetAllAnimals(OnCompleted);
      }
      function OnCompleted(items)
      {
          $find("Results").set_data(items);
      }
  </script>
  <script type="text/xml-script">
      <page xmlns:script="http://schemas.microsoft.com/xml-script/2005">
        <components>
          <listView id="Results"
              itemTemplateParentElementId="Results_layout_parent">
            <layoutTemplate>
              <template layoutElement="Results_layout" />
            </layoutTemplate>
            <itemTemplate>
              <template layoutElement="Result_item">
                <label id="Result_Name">
                  <bindings>
                    <binding dataPath="Name" property="text" />
                  </bindings>
                </label>
                <label id="Result_Category"  >
                  <bindings>
                    <binding dataPath="Category" property="text" />
                  </bindings>
                </label>
                <label id="Result_Color"  >
                  <bindings>
                    <binding dataPath="Color" property="text" />
                  </bindings>
                </label>
              </template>
            </itemTemplate>
          </listView>
        </components>
      </page>
  </script>   
</body>
</html>

  很显然,如今我们不可能再去求助于ASP.NETAJAX服务器控件ScriptManager,于是引入ASP.NET AJAX客户端脚本文件以及前面定义的PHP Web服务的工程只能靠手工编程来实现。

  接下来,请注意下面这一行代码:   

   <script type="text/javascript"

   src=" AnimalService.php/js"></script>

  在此,我们必须在php扩展名的后面添加上后缀/js,这一句通知Web服务器“告诉”相应的php代码并借助于Microsoft AJAX Library生成相应的PHP类型的Web服务的客户端代理并加载到客户端。

  事实上,你完全可以在浏览器地址栏中输入上面src属性中的内容并按回车,观察这个Web服务的客户端代理,如图4所示。

用PHP for Microsoft AJAX Library增强PHP编程

  图4 生成的客户端Web服务代理 

  仔细观察图4,你会发现这个客户端代理与在ASP.NET环境下生成的是一致的。因为我们的兴趣点也不在于ASP.NET AJAX客户端基本编程,所以在此不再赘述。

  还应注意到,为了尽可能使上面的示例典型化,我们刻意地使用了ASP.NET AJAX Futures CTP核心脚本文件PreviewScript.debug.js(当然,你也可以选用相应的release版本的PreviewScript.js)。

  根据本人的粗略分析,我们可以在PHP开发环境下利用PreviewScript.debug.js文件中的绝大部分内容。但是,工程PHP for Microsoft AJAX Library目前也存在一个极大的缺憾:我们无法使用ASP.NET平台下重要的离线数据源组件—DataSource。从某种意义上讲,DataSource组件是ASP.NET AJAX客户端编程中的重要发明,它极大地简化了客户端控件到服务器端数据的绑定。因为借助于这个控件,我们可以在xml-script声明式编程中稍经简单的配置就可以轻而易举地通过ListView或ItemView等高级数据控件访问服务器端数据。但遗憾的是,DataSource组件的设计严重依赖于ASP.NET特定服务器组件DataService。从这一点来看,开源工程PHP for Microsoft AJAX Library远未成熟起来。

  基于以上分析,因为无法利用客户端离线数据源组件DataSourceDataSource,所以,我们只好转而使用JavaScript编程方式来调用Web服务。

  在上面标记的第一部分中,我们定义了ASP.NET AJAX高级客户端数据绑定控件ListView的占位符以及相应的模板。至于相关具体细节,在此也不再赘述,有兴趣的读者可以参考位于http://asp.net/ajax/的在线ASP.NET AJAX教程。接下来,让我们讨论调用Web服务的情况。

  当点击按钮“Get Animals”时,其相应的click事件处理器GetAnimals()被激活。之后,控制转入到JavaScript代码内部并实现调用web服务方法。

  整个调用逻辑十分类似于本地方法的调用,这一切主要归功于自动生成的客户端web服务代理。接下来,在回调函数OnCompleted()中,借助于ASP.NET AJAX客户端全局方法findComponet(简写为$find)首先检索到ListView控件的实例Results,然后通过调用ListView类的set_data()方法实现对该控件的成功赋值。

  另外,在上面的代码中我们完全可以使用Microsoft AJAX Library中引入的调试技术来跟踪分析我们感兴趣的数据,在此亦不赘述。

  最后需要注意的是,在上面的xml-script声明式编程中,通过引用脚本PreviewScript.debug.js我们还可以进一步利用ASP.NET AJAX客户端编程中的许多新技术,例如转换器、校验器、动作和行为等组件来增强和扩展客户端开发。

  八、观察示例运行结果

  现在,启动你的浏览器,然后在地址栏中输入http://localhost/exNow/index.html并按回车键。如果一切顺利的话,你会看到如图5所示的初始运行快照。

用PHP for Microsoft AJAX Library增强PHP编程

  图5 示例程序初始运行时刻快照  

  然后,当你单击按钮“Get Animals”,则服务器端PHP风格的Web服务方法即被以异步方式调用。最终,服务器端的动物数据被加载并局部呈现到客户端浏览器中。下图6给出了相应的运行时刻快照。

用PHP for Microsoft AJAX Library增强PHP编程

  图6 通过PHP Web服务把服务器端数据异步加载到客户端并进行局部呈现  

  尽管上面示例页面仅仅显示了几行字符,然而这些数据却都是以Ajax方式通过客户端PHP Web服务获取的。也就是说,通过这个小小的例子,我们已经实现了既定的目标—把微软ASP.NET AJAX框架中的Microsoft AJAX Library主要技术移植到了另一种Web服务器平台PHP上。

  九、小结

  在本文中,借助于开源工程PHP for Microsoft AJAX Library,我们成功实现了利用ASP.NET AJAX客户端框架技术增强PHP Web应用程序开发的目的。需要注意的是,尽管本文示例仅仅在Windows XP系统下调试通过,但是由于Microsoft AJAX Library与PHP所具有的操作系统无关性,你肯定能够成功地把此示例运行于其他操作系统上。

  另一方面,我们也应清醒地认识到,开源工程PHP for Microsoft AJAX刚踏入正程,因此还有一片广阔的天地有待于有识之士加盟其中。

  另外,PHP+MySQL已经成为中小型网站开发的首选平台,越来越受到用户与开发人员的青睐。但是,要为PHP开发实现足够的客户端友好性(不仅仅是异步回寄和局部更新的Ajax特性),也有待于PHP平台的开发高手进行更深入的ASP.NET AJAX技术模仿性开发。