SlideShare une entreprise Scribd logo
1  sur  59
Flex 入门指南——PHP 开发者
                Mihai Corlan




欢迎访问 InfoQ 中文站 RIA 专区浏览更多 Flex、Flash 开发内容
前      言
从上个世纪 90 年代末开始,我一直从事与 Web 相关的技术,而且我接触的第一个服务器端技
术是 PHP。后来,我转向 ColdFusion 和 Java 的开发工作,但我始终认为自己是一个 PHP 开发
人员。当 AJAX 技术出现时,我开始与 Prototype 和 script.aculo.us 等架构打交道,并且着手创
建自己的架构。

2006 年底,我开始体验进行 Flex 开发。这有点类似速成学习班,因为我需要在大约 4-6 个星期
内为 FDS((Flex Data Services, 现在称为 LiveCycle Data Services)将要问世的版本创建一个演
示应用程序。尽管当时我是一个 Flex 和 FDS 的新手,但该项目进展顺利,而且我非常享受这
次开发以及学习过程。

然而,在享受的同时,我感觉到 Flex 的不同之处。我的意思是当我在进行 ColdFusion 或 Java
Web 的开发工作时,我并没有觉得其与 PHP 相比有不同之处。这仅仅是一个寻找正确的 API 以
及适应特定语言的问题。后来,当我开始在 DHTML 之上进行 AJAX 开发时,我感觉也没有不
同之处。你仍然使用相同的技巧、利用服务器端语言来创建大多数网站,以及在网站各处插入
一些趣味画面(对于本案例来说,它们是一些 AJAX widgets)。

当我使用 Flex 创建我的第一个 Web 项目时,我的天啊,这是一个巨大的转变。客户端和服务
器之间的清晰分离(除了服务器侧的业务逻辑之外的客户端侧业务逻辑)、需要进行编译而不
是翻译的客户端侧技术、以及客户端的两种语言等,所有这些均需要用一种不同于传统 Web 开
发的思维方式进行思考。

这就是我写作本文的原因。我希望与你分享一些与 PHP 相关的 Flex 特定的技巧。同时,我还
希望通过将 Flex 与 PHP 进行比较引入 Flex 概念,当然它们的比较必须是有意义的。因此本文
的目标读者是:

      希望学习更多关于 Flex 和 Action Script 3 而不只是通过简单定义能够提供的内容的
       PHP 开发人员

      已经进行 Flex 应用程序编码尝试并且希望更广更深地了解 Flex 的 PHP 开发人员

本文没有涉及的内容是什么?试图改变你或说服你让你相信 Flex 优于 X 或 Y 不是我的本意。
我坚信项目具有各种各样的类型,并且利用不同的工具能够完成这些项目。

另外,本文没有为 Flex 或 ActionScript 3 提供完整的文件资料。目前,市面上有几十本专著的
数百页资料论述该主题。关于 Flex 的文章也有成千上万篇。而我的意图是在将 Flex 概念与
PHP 类似概念进行关联是有意义的情形下,针对最重要的议题为你提供足够的信息。为了使得
本文更为实用,我对其结构进行适当的安排并且尽力避免对细节进行过多的赘述。在本文的结
尾部分,我提供了 Adobe AIR 的简介和一些附加参考资料,以便于你能够查阅与本主题相关的
更多详细信息。
最后需要说明的是,对于本文给出的大部分范例,我选择使用 Flex 3 进行编程。作出这样的选
择有如下几个原因:首先,在写作本文时,Flex 4 仍然是 beta 版本。其次,由于 Flex 4 主要是
Flex 3 的演化版本,因此这里涉及的大部分应用程序能够适用于 Flex4,只需进行少许更改即
可。在一些范例中,我将指出这些不同之处。对于 PHP 范例,我选择使用 PHP 5.3 作为编程参
考语言。前面已经给出说明,现在让我们来看看下面的本文目录,然后开始用功学习。

                              Mihai Corlan ——Adobe 平台技术经理
目                        录
什么是 Flex? .......................................................................................................................... 5
  Flex: 一个框架绑定的两种语言 .............................................................................. 5
  为什么你需要关注 Flex.............................................................................................. 6
  从瘦客户端向智能/富客户端演化.......................................................................... 7
MXML 语言简介.................................................................................................................... 8
  MXML 和 ActionScript 3 之间的混合 .............................................................. 12
    CSS 式样 ....................................................................................................................... 13
    在运行时修改 MXML 代码 ................................................................................... 15
ActionScript 3 语言简介 ................................................................................................... 17
        隔离语句........................................................................................................................ 17
        数据类型、变量和常量 ........................................................................................... 17
        函数和匿名函数(闭包) ...................................................................................... 22
        OOP:类和接口......................................................................................................... 24
        变量作用域 ................................................................................................................... 36
        数组 ................................................................................................................................. 37
        命名空间........................................................................................................................ 39
        与 XML 的配合 .......................................................................................................... 42
     动态 ActionScript ...................................................................................................... 44
Flex 是异步的 ....................................................................................................................... 45
数据绑定、元数据标签和反射 ...................................................................................... 46
我的数据在哪里?将它显示出来!............................................................................. 52
Flex 和 PHP 项目的用户授权 ........................................................................................ 54
建立 Flex 和 PHP 项目...................................................................................................... 54
  Flex SDK 和文本编辑器 ......................................................................................... 55
  Flex Builder / Flash Builder 和 Eclipse PDT / Zend Studio ..................... 55
  调试 Flex 应用程序 ................................................................................................... 55
什么是 Adobe AIR.............................................................................................................. 56
下一步计划是什么? ......................................................................................................... 57
总结 ........................................................................................................................................... 58
什么是 Flex?
最简单的回答是:Flex 仅仅是创建 Flash 应用程序的另一种方法。Flash 应用程序是在 SWF 文件
中编译的,并且由 Flash Player 在浏览器中进行播放。为什么我们需要使用另一种方法创建
Flash 应用程序?传统的 Flash 应用程序是使用 Flash 制作工具创建的。如果你查看一下该工
具,你会发现它主要适用于设计人员。其中包括一个舞台(stage),一条时间轴线(timeline)
以及各种绘画工具等。

当你在开发应用程序并且追求开发效率时,你需要各种组件,你希望通过重用代码尽可能地提
高开发效率,最后但并不是最不重要的一点是,你需要一个新型的 IDE。

因此,一种修正的回答可能是:Flex 是一种能够帮助开发人员快速创建富因特网应用程序
(Rich Internet Application)的开源框架,这些应用程序能够在 Flash Player 中运行。在 2006 年
的今天,随着 Flex 2、Flash Player 9 和 ActionScript 3 的推出,该框架已经趋于定型。目前的版
本是 Flex 3,2010 初,其下一个版本 Flex 4 将要面世。




Flex: 一个框架绑定的两种语言
在 Flex 之下,你将发现下列语言和工具:

     两种语言:MXML 和 ActionScript 3。Flex 提供两种语言以便创建 Flex 应用程序。在下
      面的章节中,我将进一步地讨论每种语言。

     一个富组件库

     各种编译器和调试器

     用于编译和调试 Flex 应用程序的各种命令行工具

由于 Flex 是一种开源框架,因此我极力推荐你访问该计划的主页
http://opensource.adobe.com/flex 并且下载相关的 SDK。你能够从组建库中查阅到所有组件的源
代码,你能够查询相关的开放程序缺陷和功能库(http://bugs.adobe.com/flex),以及查看各种
规范的 wiki 页面。

Flex 提供的部分效率改善应该归功于其海量组件库。该组件库包含了所有你能够想象的 UI 组件
(例如,各种输入框(input box)、面板(panel)、视窗(window)、滑动条(slider)、数据
网格(data grid)、组合框(combo box)、折叠显示(accordio)和 Tab 设置(tab set)等
等)。另外,该组件库还包含各种布局容器和表单元素。在下面的图中,你能够看到 Flex 3 可
以提供的各种 UI 组件的屏幕截图(点击可以放大)。




如果这些组件仍然不够使用,则你可以进入相应的源代码,扩展这些组件以创建你自己的组件
或从零开始创建新的组件。



为什么你需要关注 Flex
在深入探讨什么是 Flex 之前,让我们暂停一下,重温为什么你需要关注 Flex 的原因。

传统的 HTML Web 应用程序具有“请求-响应”架构。在浏览器发送一个请求之后,相应的服务
器回送一个页面,这样的周期不断重复。HTML 和 CSS 为呈现该信息提供了卓越的选择, 正
如可提出证据加以证明的那样,这是目前最佳的选择之一。然而,随着时间的推移,这种架构
不仅局限于静态呈现,而已经扩展至应用程序平台。利用脚本技术,我们尝试创建动态页面以
及设计服务器使得其能够对特定请求给出响应。更进一步地,通过添加 DHTML 和 AJAX ,我
们能够将新的气息带入由 Web 服务器支持的页面:用户能够与载入页面互动并且在无需刷新整
个页面的情形下改变相关的视图。

随着这些技术的演化,各种复杂的应用程序不断出现。一些 Web 应用程序已经开始复制许多桌
面应用程序的功能而且同时能够保持 Web 应用程序的便利性(只要有浏览器和因特网连接的地
方就能够使用 Web 应用程序)。因此,各种在线版本的电子制表软件和文本编辑器不断涌现。

然而,从可用性的角度来看,在线应用程序的用户友好界面要比桌面应用程序差。同时,如需
创建这些复杂的 Web 应用程序,你必须掌握许多技术(JavaScript、DHTML、CSS、AJAX 库
以及服务器端等技术 )的各种技巧,并且你必须具有处理不同浏览器之间差异的经验以及了解
他们是如何实现 HTML/CSS/JS 的。因此,2002 年,Macromedia 提出了术语 RIA(Rich Internet
Applications)来描述一种结合了 Web 应用程序的优势和桌面应用程序的益处的新型应用程序。
能够实现这一新型应用程序的技术就是 Flash Player。

通常,如果你希望创建应用程序(而不仅仅是一个 Web 站点或 Web 页面),你可以使用 Flex
来实现。一些应用程序几乎不能使用 HTML/JavaScript 来创建,而另外一些应用程序很难跨浏
览器一致运行。Flash Player 能够提供最好的图形引擎,它已经安装于 98% 的具有因特网连接
的计算机,并且能够将声音和图像视为“一等公民”。它支持麦克风(microphone)和 Web 摄像
(webcam)功能、支持流媒体和数据推送(streaming and data pushing)服务、以及提供卓越的
字体排印(typography)功能,其支持的功能可以填满很长的清单。

请看看下面三个应用程序以便了解使用 Flex 能够出现什么样的奇迹:

     SumoPaint 是一个免费使用的图像编辑应用程序;

     Mindomo 是一个思维导图应用程序;

     Times Reader 是一个源自《纽约时报》(The New York Times)的应用程序。

随着时间的推移,其他技术已经进入 RIA 领域。除了使得如 Gmail 或 Google Spreadsheets 等应
用程序成为现实的 AJAX 不断发展之外,今天,我们还能够看到源自 Microsoft 的 Silverlight 应
用程序以及源自 Sun 的 JavaFX 应用程序。



从瘦客户端向智能/富客户端演化
让我们回到浏览器以及 Web 应用程序是如何传送的。当浏览器发出一个请求,相应的服务器将
使用静态内容(HTML/CSS/JS 代码)和脚本(这些脚本可能查询数据库或调用其他脚本,但最
终他们会输出 HTML/CSS/JS)的组合来准备一个页面。该页面由浏览器载入并且显示出来。在
此,一个关键元素是,通常该页面(或响应)具有显示标记(presentation markup )以及烘焙至
相同消息的数据。

当应用程序的新状态需要呈现时,浏览器发出一个新的请求,之后相应的服务器将准备请求的
页面。而客户端“仅仅”显示该数据。

Flex 应用程序以不同的方式工作。服务器发送已编译过的 Flex 应用程序 (SWF 文件) ,该应用
程序能够在浏览器中使用 Flash Player 插件运行。通常,该 SWF 文件只能支持客户端侧的业务
逻辑。如果需要数据(例如来自数据库),则 Flex 应用程序能够发送请求以获得这些数据。服
务器只发送数据(数据的格式可以为 XML、JSON 或 AMF3),并且客户端能够知道如何显示
该数据。我们这里讨论的是面向服务的架构:

Flex 应用程序实际上是客户端–一种能够使用由服务器提供的数据服务的客户端。该应用程序能
够在浏览器不刷新页面或不重新装载 SWF 文件的情形下变更状态。该应用程序是一种能够不
仅仅显示数据的客户端。因此,通过利用 Flex 和 Flash Player 能够创建几乎任何对象,这些对
象对于在 Web 上部署各种游戏、应用程序以及 widget 具有重要意义,而这些游戏、应用程序
以及 widget 能够与“古典”Web 应用程序以及其他应用程序进行集成。
到此为止,已经谈论太多的枯燥理论,让我们看看一些程序代码吧!




MXML 语言简介
MXML 是一种陈述性的、基于 XML 的语言。在 Flex 应用程序中,你可以使用 MXML 语言快
速地创建应用程序的结构/外观。在 Flex 中,你使用 MXML 能够创建的应用程序,也可以使用
ActionScript 3 来创建。然而,反向操作不能成立。

如果你能够使用 ActionScript 3 来创建可以使用 MXML 完成的应用程序,那么为什么 MXML 会
首先出现?通常学习和理解利用 XML 语言描述的用户界面比利用命令式语言描述的用户界面
要简单得多。这样利用 XML 语言编写的用户界面将会具有较少的代码。另外,为陈述性语言
建立工具比为命令式语言也简单得多。下面是利用 MXML 实现的一个范例“Hello world!”。

  1: <Label text="Hello World!" fontSize="14" color="red" x="100" y="50"/>


在这段代码中,我使用了一个名称为 Label 的 Flex 组件在屏幕上显示若干文本字符。我将文本
的属性设置为我期望的文本格式。另外,我希望能够对外观及该 Label 在屏幕上的位置进行
(少许)客户化处理。因此,我使用了属性 fontSize、color、x 和 y。我相信你会同意这是非常
易于理解和学习的范例。

现在,考察一下利用 ActionScript 3 实现的相同范例:

  1: var myLabel = new Label();

  2: myLabel.text = "Hello World!";

  3: myLabel.setStyle("fontSize", "14");

  4: myLabel.setStyle("color", "red");

  5: myLabel.x = 100;

  6: myLabel.y = 50;

  7: addChild(myLabel);


我使用了 7 行代码来实现前面我仅用包含一个标记和若干属性的 MXML 实现的范例!现在,
可以设想一下在一个真正的应用程序中,你采用大量的控件,并且在不同的容器中进行分组。
那么,维护利用 MXML 编写的代码要比维护使用几百行 ActionScript 3 编写的代码更为简单。

尽管你能够使用 MXML 描述你的应用程序,但你不能使用 MXML 实现你的应用程序的业务逻
辑。而你可以利用 ActionScript 3 实现这一目的。

Flex 应用程序能够运行于 Flash Player,而 Flash Player 只能支持 ActionScript 2 和 ActionScript
3。这意味着你在应用程序中编写的任何 MXML 代码必须通过相应的 MXML 编译器转换成
ActionScript 3 代码。然后,该代码通过 ActionScript 编译器被转换成 Flash Player 支持的字节代
码(bytecode)(SWF 文件)。
因此,几乎每个 MXML 组件的后面均存在一个 ActionScript 3 类(实际上,有些 MXML 标记没
有相应的 ActionScript 类,例如 Script 和 Model)。在下面的范例中,这是一个源自 Label 类的
一个代码片段( snippet ):

   1: public class Label extends UIComponent

   2:                           implements IDataRenderer, IDropInListItemRenderer,

   3:                           IListItemRenderer, IFontContextComponent

   4:

   5: {

   6:       /**

   7:           *    Constructor.

   8:           */

   9:       public function Label()

  10:       {

  11:                super();

  12:

  13:                // this is so the UITextField we contain can be read by a screen-reader

  14:                tabChildren = true;

  15:       }

  16:

  17:       /**

  18:           *    @private

  19:           *    Flag that will block default data/listData behavior.

  20:           */

  21:       private var textSet:Boolean;

  22:

  23: ...

  24: }


In any Flex application you have at least one MXML file, which is the main application. For example,
here is the complete code for the “Hello World!” application:
在任何 Flex 应用程序中,你应该至少具有一个 MXML 文件,这是主应用程序。例如,下面是
“Hello World!” 应用程序的完整代码。

  1: <?xml version="1.0" encoding="utf-8"?>

  2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

  3:         <mx:Label text="Hello World!" fontSize="14" color="red" x="100" y="50"/>

  4: </mx:Application>


根节点必须总是 Application,而且这是定义命名空间的位置。在本范例中,我仅仅提供一个用
于 MXML 语言和 Flex 组件的命名空间:mx(上面的代码是使用 Flex 3 编写的。如果使用 Flex
4,则代码具有微小的差异,其中声明了多个命名空间)。

如果你编写自定义组件,则必须为其添加一个命名空间。例如,在下面的代码中,我声明了第
二个命名空间指向我所创建的所有组件(在本范例中,我使用了一个我自己创建的名称为
MyCustomLabel 的自定义 label 组件):

  1: <?xml version="1.0" encoding="utf-8"?>

  2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*">

  3:    <mx:Label text="Hello"/>

  4:    <local:MyCustomLabel text="world!"/>

  5: </mx:Application>


到目前为止,你也许想知道 Flex 应用程序是如何处理不同页面的。对于 HTML Web 站点,通
常不同状态是在不同页面实现的。而 Flex 应用程序与桌面应用程序非常相似。这意味着你只需
使用一个 MXML 文件,即可在该页面上显示应用程序的不同状态。Flex 能够提供许多手段来
实现这一目的,这些方法包括使用如折叠显示(Accordion)、Tab 设置浏览器(Tabsets
navigator)和牌布局管理器(Card layout)的 Flex 组件以及 Flex 模块等。

你已经看到 MXML 代码能够用于定义应用程序的外观。但你也能够利用它并且通过扩展现有
Flex 组件创建自定义组件。让我们来看一个范例。假设在你的应用程序中具有若干表单,这些
表单具有两个按钮:Save 和 Cancel。观察一下该 MXML 自定义应用程序的代码(该代码是在
一个名称为 FormButtons.mxml 的文件中创建的。所有 MXML 文件必须使用 mxml 扩展名)。

  1: <?xml version="1.0" encoding="utf-8"?>

  2: <mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="150">

  3:    <mx:Button id="saveButton" label="Save"/>

  4:    <mx:Button id="cancelButton" label="Cancel"/>

  5: </mx:HBox>
当你创建自定义应用程序时,你能够选择需要扩展的任何组件(但你不能对 Application 进行扩
展)。我选择扩展 HBox (Horizontal Box),这是一个能够在相同行显示所有 children 的容器。在
该容器的内部,我添加了两个按钮,一个用于 Save,另一个用于 Cancel。我还为每个按钮设置
了 id 属性。你可以使用 id 属性值作为引用代码其他部分的对象的一种方式。这与在
ActionScript 代码中声明一个变量的方式是相同的。

现在,让我们看看你如何在一个 Flex 应用程序中使用该自定义组件:

   1: <?xml version="1.0" encoding="utf-8"?>

   2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*"

layout="horizontal">

   3:     <mx:TextInput width="150"/>

   4:     <local:FormButtons/>

   5: </mx:Application>


Below you can see how the application looks:




你也许会认为在 MXML 中你只能使用视觉 Flex 组件(即最终能够被显示的组件)。实际上,
这是不确切的。你可以使用表示数据的 MXML 标签(用于存储数据的对象)或操作数据的组
件(能够从服务器查询数据或向服务器发送数据的组件)。下面,你能够看到一个 generic 对象
组件的范例,该组件具有一个名称为 name 的特性(property):

   1: <mx:Object id="myObj" name="Mihai Corlan"/>


正如我前面所述的那样,与 Flex 相伴的所有(几乎所有)Flex 组件均具有 ActionScript 类,该
类能够实现视觉外观(如果有的话)以及相应的逻辑。当你选择使用 ActionScript 而不是
MXML 创建一个自定义组件(不论其是否是视觉组件)时,你必须记住存在以下限制:在不带
自变量的情形下,该类的构造器(constructor)必须能够被调用(如果具有自变量,则这些自变
量应该具有默认值)。
MXML 和 ActionScript 3 之间的混合
返回到自定义组件 FormButtons (具有两个按钮的组件),你也许注意到一个问题:如果你希望在
一个 Save 和 Cancel 标签不起作用的地方使用该组件将会怎样?你应该创建另一个带有你期望
的标签(例如 Show 和 Hide)的自定义组件吗?当然,这是一个选择,但这个组件不能缩放或
外观不太优雅!你所真正期望的是一个更为通用的组件,以及一种使用代码变更组件的方法。
这是为什么迟早你不得不在 MXML 代码中添加 ActionScript 代码。

在下面的范例中,我在组件的 MXML 代码中添加了 ActionScript 代码以定义两个存储了按钮使
用的标签的变量。注意,我使用了一个新的标签 Script,并且在该标签之中使用了 CDATA。这
是因为在 XML 文档之中,像>、<和& 等字符是非法的(如果它们没有换码)。另外,现在我
将不会把太多重点放在 ActionScript 代码上,但我将在后面的章节中更深入地讨论 ActionScript
代码。

   1: <?xml version="1.0" encoding="utf-8"?>

   2: <mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="150">

   3:    <mx:Script>

   4:         <![CDATA[

   5:               public var label1:String = "Save";

   6:               public var label2:String = "Delete";

   7:         ]]>

   8:    </mx:Script>

   9:    <mx:Button id="saveButton" label="{label1}"/>

  10:    <mx:Button id="cancelButton" label="{label2}"/>

  11: </mx:HBox>


我定义的变量可以在使用该组件的 Flex 应用程序中设置。下面,让我们来看看在使用新的自定
义组件之后,变更的 Flex 应用程序代码的构成。

   1: <?xml version="1.0" encoding="utf-8"?>

   2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*"

layout="horizontal">

   3:    <mx:TextInput width="150"/>

   4:    <local:FormButtons label1="Show" label2="Hide"/>

   5: </mx:Application>


注意,FormButtons 标签具有两个属性: label1 和 label2。这是为什么你能够在这些按钮上设置
期望显示的文本。并且这是你使用的机制以便将更多的行为添加至 MXML 组件(使用
ActionScript 代码)。在真正的应用程序中,你可能希望将一个行为与每个按钮进行绑定,以便
当按下按钮时,就会产生相应的结果。你可以使用 ActionScript 代码编写通过按下按钮即可触
发的各种函数。

另外,还有一种在 MXML 至添加 ActionScript 代码的方法。你可以先创建一个 ActionScript 文
件(在本范例中,该文件的名称为 buttons.as),然后将该文件包含于 MXML 文件中。你可以
通过添加一个具有 source 属性的 Script 标签实现这一操作 ,而该属性指向该 ActionScript 文
件。下面是这一方法的代码。

 1: // ActionScript file called buttons.as

 2: public var label1:String = "Save";

 3: public var label2:String = "Delete";




 1: <?xml version="1.0" encoding="utf-8"?>

 2: <!-- MXML component file called FormButtons.mxml a-->

 3: <mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="150">

 4:    <mx:Script source="buttons.as"/>

 5:    <mx:Button id="saveButton" label="{label1}"/>

 6:    <mx:Button id="cancelButton" label="{label2}"/>

 7: </mx:HBox>




现在,让我们后退一小步,然后推测一下当 MXML 编译器解析 FormButtons.mxml 文件时会发
生什么情况。你已经知道所有代码将会转换成 ActionScript 代码。但对于我添加的现有
ActionScript 代码(两个变量)会发生什么情况呢?MXML 编译器将会把每个 MXML 文件编译
至一个 ActionScript 类。在这种情形下,我将获得一个名称为 FormButtons(因为这是该文件的
名称并且它可以用于该类的名称)的类,该类扩展了 HBox 组件(因为我选择了 HBox 作为该
组件的根节点)。该类中的所有 ActionScript 代码将会变成该类的成员:变量(例如本范例中
的变量)将会变成实例变量,并且函数将会变成实例方法。



CSS 式样
到目前为止,你也许想知道你是否能够改变视觉 Flex 组件的外观。Flex 组件具有类似 HTML
CSS 的技术?答案是肯定的,Flex 支持 CSS。在 Flex 4 中,对 CSS 的支持已经扩展至允许不仅
可以基于类的名称而且可以基于 ID 进行式样定义,以支持伪选择符(pseudo-selector)(例
如,对于一个按钮来说,你应该具有下选择符(down selector)、上选择符(over selector)等
等)以及其他更多功能。

与在 HTML 中一样,式样可以在行中(在 MXML 代码内部)定义或在一个独立的文件中定
义。让我们先回到自定义组件 FormButtons, 然后设置若干式样。如果你选择在一个独立的文件
中定义试样,则必须使用一个 Style 标签并且将路径设置为 source 属性中的式样文件。



  1: <?xml version="1.0" encoding="utf-8"?>

  2: <!-- MXML component file called FormButtons.mxml a-->

  3: <mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="150">

  4:    <mx:Style>

  5:        .Button1 {

  6:              font-size: 14;

  7:              color: #990000;

  8:        }

  9:    </mx:Style>

 10:    <mx:Script source="buttons.as"/>

 11:    <mx:Button id="saveButton" styleName="Button1" label="{label1}"/>

 12:    <mx:Button id="cancelButton" label="{label2}"/>

 13: </mx:HBox>


我创建了一个名称为 Button1 的 CSS 类,该 CSS 类定义了标签颜色以及字体大小。然后,我使
用第一个按钮的 styleName 属性将式样设置为第一个按钮。至此,该应用程序如下图所示:
CSS 式样在运行时能够改变(在 Flex 应用程序载入浏览器之后),并且该应用程序的外观也会
立即随着改变。

在 Flex 4 中,Adobe 添加了名称为 MXML 用于图形的新语言,该语言添加了原语
(primitive)、效果(effect)、面具( mask) 和 2D 转换功能。你可以使用这些新的标签在
MXML 文件中创建皮肤(skin)类,然后你能够将该类设置为你期望对其进行皮肤粘贴的组
件。在下图中,你能够看到一串以 Flex 4 为皮肤的图像。左边给出了该串图像的默认状态,而
右边给出了该串图像的打开状态。你可以点击这里 观看处于运行状态的应用程序。




当你在关于 Flex 应用程序外观的自定义的文档中徘徊时,你也许能够理解术语“皮肤粘贴”的含
义。你可以进行图形皮肤粘贴(graphical skinning )或编程皮肤粘贴(programmatic skinning )
以便改变相应的外观。点击这里 可以获得关于这方面问题的佳文。



在运行时修改 MXML 代码
有时候你希望在运行时变更 UI 组件。也许你希望根据你从服务器中检索到的数据来实时地建
立一个表单。同样,你也能使用 ActionScript 代码实现这一任务。任何视觉 Flex 组件均具有添
加一个新子类、移除一个新子类以及获取所有子类等方法。如果你愿意,你可以将这些方法与
在 HTML 中使用 JavaScript 改变 DOM 的方式进行比较。然而,它们之间存在差异:利用
JavaScript 你可以注入你从服务器检动态索到的 HTML 代码(通过一个 AJAX 调用)。但在
Flex 中,这是不可能,并且在 Flex 中不存在 eval() 函数。然而,在主应用程序载入之后,有方
法可以载入其它 Flex 应用程序或 Flex 模块。

当你了解一个组件的所有不同视图时,你能够使用 MXML States 来实现相同组件或应用程序的
不同状态。状态功能是 Flex 4 对比 Flex 3 的实现方式改善非常显著的地方,这使得这些状态更
加易于使用并且添加更多功能。在 Flex 4,状态的工作方式如下:
1.   你可以定义若干状态并且指定默认状态

    2.   你能够指定在一个特定的组件应该出现在哪些状态中

    3.   你可以指定在状态出现的位置每个状态的任何属性的独立值

假设你希望创建一个处理应用程序登录功能的组件。你希望使用该组件显示登录表格,并且在
登录成功之后,你希望显示退出按钮以及用户姓名。

下面是使用 Flex 4 创建的登录/退出组件:

   1: <?xml version="1.0" encoding="utf-8"?>

   2: <s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"

xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/halo">

   3:     <s:states>

   4:         <s:State name="notlogged"/>

   5:         <s:State name="logged"/>

   6:     </s:states>

   7:

   8:     <s:TextInput includeIn="notlogged" text="user name"/>

   9:     <s:TextInput includeIn="notlogged" text="password"/>

  10:     <s:Button includeIn="notlogged" label="Login" click="{currentState='logged'}"/>

  11:

  12:     <mx:Label includeIn="logged" text="Current user: Mihai Corlan"/>

  13:     <s:Button includeIn="logged" label="Logout" click="{currentState='notlogged'}"/>

  14:     <s:layout>

  15:         <s:HorizontalLayout/>

  16:     </s:layout>

  17: </s:Group>


上面的代码应该是很容易理解的。作为顶部容器,我使用一个具有设置为 HorizontalLayout 布
局的 Group 组件(这与用于上面范例 Flex 3 中的 Hbox 具有相同的效果)。我已经在该文件的
顶部为该组件定义了可用状态。接下来,我还定义了按钮、文本输入和标签。注意一下指定该
组件在什么状态下会出现的 includeIn 属性。另外,文件中还包含一个 excludeFrom 属性。如果
你希望在所有状态下定义一个按钮,则无需为这两个属性指定任何状态。最后,你可以看到我
为这两个按钮的点击属性指定了一个表达式。例如,表达式 click=”{currentState=’logged’}” 告
诉 Flex 当按钮被点击时,应该将该组件的状态改变为名称为 logged 的状态。
尽管我一直在讨论 MXML 语言,但我已经将越来越多的 ActionScript 代码加入了这些范例。这
是一个迹象:该到讨论第二种 Flex 语言 ActionScript 3 的时候了。




ActionScript 3 语言简介
ActionScript 3 是一种动态的面向对象的脚本语言,它是(或几乎是)一种类型安全的语言。
ActionScript 3 基于 ECMAScript 3 规范 (ECMA-262)。另外,其某些功能也是符合 ECMAScript
4 的相关建议。我已经发现采用下列方式对完全是 ActionScript 3 新手的开发人员解释该语言是
最容易的:ActionScript 很像 JavaScript 和 Java 的一个混合语言,并且其具有很强的个性。实际
上,JavaScript 是另一种基于 ECMAScript 规范的语言,因此,其与 ActionScript 自然而然地具
有许多共同点。

正如我前面所述的那样,Flash Player 能够运行两种语言:ActionScript 2 和 ActionScript 3。
Flash Player 在其内部使用两种不同的虚拟机(Virtual Machine)来协调这两种语言
(ActionScript 3 和 AVM2 Virtual Machine 是在 Flash Player 9 中推出的)。ActionScript 3 是由
核心语言(关键字和数据类型等 ) 以及 Flash Player API (该 API 使得开发人员能够通过显示列表
API( display list API)、3D API、绘画 API(drawing API)以及动画(Animation)等 API 使
用所有 Flash Player 功能)构成的。在本文中,我将侧重讨论核心语言。点击 这里 ,你可以获得
一篇关于 ActionScript 3 的入门佳文。

从现在开始,我将使用缩写“AS3” 替换 “ActionScript 3”。



隔离语句
在 PHP 语言中,你可以使用分号(;) 来隔离或结束一条语句。而在 AS3 语言中,你可以使用分
号(;) 或仅仅行尾符。但我必须说,当我看到不用分号编写的代码时,我的眼睛将不会出现喜悦
的目光。因此,我建议你使用与 PHP 使用的相同方法。



数据类型、变量和常量
PHP 具有下列数据类型:布尔(Boolean)、整数(integer)、浮点数( floating point
number)、字符串( String)、数组(Array)、对象( Object)、资源( Resource)和
NULL。

对于 AS3 来说,我们具有下列数据类型:

      顶级数据类型:布尔(Boolean)、整数(int)、单元(uint)、数( number)(与
       PHP 的浮点数相同)、字符串( String)、Null (仅包含一个值:null)和 void (仅包含一
       个值:undefined)
   复杂数据类型:对象( Object)、数组(Array)、矢量(Vector )(以 Flash Player 10
       开头)、字典(Dictionary)、位图(Bitmap)、字节数组(ByteArray)、日期
       (Date)、XML、XMLList、函数(Function)、错误(Error)和 RegExp 等。

在 AS3 语言中,一个变量就是与实际值关联的一个标识符或指针。AS3 中的合法值可以是对象
(int 或 uint 是对象,Number 或 Date 也是对象)、null 和 undefined。null 和 undefined 均表示数
据缺失,但它们之间存在差别。当你声明一个变量并且你没有对其初始化时,并且如果变量的
类型不是 Boolean、int、uint 或 Number,则该变量具有值 null 。如果变量没有赋予数据类型并
且没有初始化,则该变量具有值 undefined。同时,当你拥有一个动态对象并且希望检查一个特
定的方法或特性(property)是否被定义时,你可以对 undefined 进行检查。



在 PHP 中,你可以按照下面的方式声明一个变量:

  1: $anInteger = 12;

  2: $isTrue = true;

  3: $aString = "my string";

  4: //or

  5: $aString = 'my string';


在 AS3 中,你可以使用 var 关键词声明一个变量:

  1: var anInteger:int = 12;

  2: var isTrue:Boolean = true;

  3: var aString:String = "my string";

  4: //In AS3 you can not use simple quotes for declaring a String


注意在该变量名称之后,我添加一个类型注解;例如,myVarName:Boolean (该类型是使用 “:”
声明的,后面紧跟相应的类型)。在 AS3 中,你可以使用类型注解,也可以不使用类型注解
(如果编译器设置为严格模式(strict mode ),则你必须使用类型注解)。

对于 PHP 来说,你不必声明变量的类型,因此,这一点也许显得奇怪,而且你可能希望坚持使
用不指定类型的方式编写程序。由于使用类型注解具有诱人的优点,我强烈推荐你使用类型注
解。首先,当你使用 IDE 编写代码时,对变量进行分类将使得你在编译时发现更多错误。例
如,设想具有一个单一 String 自变量的函数。如果你试图调用该函数,将一个 Object 作为自变
量进行传递,则 IDE 将提醒你这是错误。

如果不使用类型注解,你可能会遇到运行时错误,但只能在你或最终用户运行该应用程序时才
会发现,并且此时查明软件缺陷的根源将会非常困难。

坚持使用类型注解的第二个原因是,如果 AS3 编译器知道变量的特定类型,则其能够对应用程
序进行优化。
在 PHP 中,你能够利用每次赋值改变变量的类型:

 1: $myVar = 12; //it is an int

 2: $myVar = "now is a string";


在 AS3 中,只有当你使用“*”声明变量为 untyped 时,你才能够完成相同当操作(使用严格模
式)。

 1: var myVar:int = 12;

 2: //this will raise an error and the application can not be compiled

 3: myVar = "this is a string";

 4:

 5: //declaring the variable untyped you can change the type with each assignment

 6: var myVar2:* = 12;

 7: myVar2 = "this is a string now";


你可能注意到只有当声明变量时我才使用关键词 var。对于下一步赋值操作,你可以忽略 var 和
类型注解。

正如我前面所述的那样,在 AS3 中变量仅仅是实际值的指针。然而,当你将 int、uint、
Number、Boolean 或 String 变量赋值给另一个变量时,将会创建一个副本(对于将这些类型的
一个变量传递给一个函数时,情况也是相同的)。在 PHP 中,你可以使用 “&” 运算符通过引用
为原语类型进行变量赋值;当你为一个变量改变值时,其它变量将指向相同的改变值。



在 PHP 中,你使用“.” (dot)对字符串进行串接,而在 AS3 中,你可以使用“+” (plus)完成相同的
任务:

 1: //in PHP

 2: $space = " ";

 3: $a = "this" . $space . "is!";

 4:

 5: //in AS3

 6: var space:String = " ";

 7: var a:String = "this" + space + "is!";


在 PHP 中,你可以在任何你期望的位置定义变量:例如在文件级、在函数中或在类中。在 Flex
应用程序中,变量只能在函数中或类级别中声明。
此外,在 PHP 中,你可以编写一段没有在函数中声明的过程化程序代码(procedural
programming ):

  1: <?php

  2:

  3: $a = 1;

  4: for ($i=0; $i<100; $i++) {

  5:      $a += $i * $a;

  6: }

  7:

  8: ?>


在 AS3 中,你不能利用函数之外的变量进行任何操作(尽管你可以在函数之外声明变量),但
有一个例外,我将在 Class 章节讨论它。因此,如果你试图运行下面的代码,你将在编译该应
用程序时出错。

  1: <?xml version="1.0" encoding="utf-8"?>

  2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

  3:      <mx:Script>

  4:           <![CDATA[

  5:           var a:int = 1;

  6:           for (var i:int = 0; i<100; i++) { //this raises an error

  7:                 a += i * a;

  8:           }

  9:           ]]>

 10:      </mx:Script>

 11: </mx:Application>


这是你为什么你可以通过重写该代码以便其能够正常运行:

  1: <?xml version="1.0" encoding="utf-8"?>

  2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

  3:      <mx:Script>

  4:           <![CDATA[

  5:           var a:int = 1;
6:

   7:          function calculations(a:int):int {

   8:                for (var i:int = 0; i<100; i++) {

   9:                     a += i * a;

  10:                }

  11:                return a;

  12:          }

  13:          ]]>

  14:      </mx:Script>

  15: </mx:Application>


在 PHP 中,可以按照下面方式声明和使用常量。

   1: //constants

   2: define("CONSTANT", "Hello");

   3: $myString = CONSTANT . ‘ world!’;


在 AS3 中,可以使用 const 关键词声明常量(使用大写字母命名常量是一个惯例):

   1: static const HELLO:String = "Hello";

   2: var myString:String = HELLO + " world!";


什么可以用于变量的名称呢?对于 PHP 和 AS3 来说,这一点是相似的:只要名称的第一个字
符为字母或在“_”之后跟随字母、数字或下划线,该名称即为合法名称。对于两种语言来说,下
面均是合法变量名称的范例:_1, _a1A, b。

在 PHP 中,通过了解其字符串名称,你可以使用该变量:

   1: <?php

   2: $myVar = 12;

   3: $varName = 'myVar';

   4: echo($$varName); //print 12;

   5: ?>


在 AS3 中,通过使用引用成员的动态方法(变量/方法),你可以获得相似的功能:

   1: <?xml version="1.0" encoding="utf-8"?>

   2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"

creationComplete="init()">
3:     <mx:Script>

  4:         <![CDATA[

  5:

  6:               var myVar:int = 12;

  7:

  8:               function init():void {

  9:                    var varName:String = "myVar";

 10:                    trace(this[varName]); //output 12

 11:               }

 12:         ]]>

 13:     </mx:Script>

 14:

 15: </mx:Application>


在该范例中,我使用了 this 来引用当前对象,但你可以对任何对象使用相同对技巧。当讨论动
态类时,我将用更多当篇幅来对此进行说明。



函数和匿名函数(闭包)
在 AS3 中,你可以利用函数实现你可以在 PHP 中实现的每一件事,甚至更多事情。首先,在
AS3 中,你可以定义自变量类型和返回类型(在 PHP 中,你只能从对象添加类型注解至方
法)。

  1: function calculate(x:int=0, y:int=0):int {

  2:     return x + y;

  3: }

  4: //using the function

  5: var result:int = calculate(1, 2);

  6:

  7: function calculateAverage(...arguments):Number {

  8:     var result:Number = 0;

  9:     for (var i:int=0; i<arguments.length; i++) {

 10:         result += arguments[i];
11:     }

 12:     return result/arguments.length;

 13: }

 14:

 15: //using the function

 16: var result:Number = calculateAverage(1, 2, 3, 4, 5, 6);


你可以将… (rest) 运算符与显示自变量进行混合,只要你将… (rest) 运算符作为自变量列表的最
后一个元素放置即可:function foo(x:int, y:int, …arguments):Number {}。当你希望利用自变量中
的一个变量成员创建函数时,… (rest) 运算符是非常有用的。

如果函数无需返回任何值,你可以使用 void 作为返回类型。

在 PHP 和 AS3 中,你可以为自变量提供默认值。例如:

  1: //php code

  2:

  3: function doThing($a, $b="default value") {

  4:     echo $a . $b;

  5: }

  6:

  7: //AS code

  8: function doThing(a:String, b:String="default value"):void {

  9:     trace(a + b);

 10: }


当然,你可以在函数中定义函数(你将在下一个代码样本中看到一个范例)。

其次,在 AS3 中,任何函数将被表示为 Function 类的一个实例。这使得某些有趣的事成为可
能:

        你可以创建一个文字函数并且将它赋值给一个变量,然后通过该变量调用该函数(这
         在 PHP 中也能够实现)。

        你可以返回一个函数作为另一个函数的执行结果。

        当调用其它函数时,你可以将函数作为自变量传递。

  1: var f:Function = function multiply(x:int, y:int):int {

  2:     return x*y;
3: }

  4:

  5: trace(f(3,5));

  6:

  7: function giveMeAFunction():Function {

  8:     return function multiply(x:int, y:int):int {

  9:          return x*y;

 10:     };

 11: }

 12:

 13: var h:Function = giveMeAFunction();

 14: trace(h(3,4));


在 PHP 和 AS3 中,你可以创建匿名函数(闭包)。在前面的代码样本中,你能够看到一个在
giveMeAFunction() 中创建一个匿名函数然后将其返回的范例。

也许 AS3 和 PHP 的函数之间的最大不同点是你定义它们的方式。在 PHP 中,你可以在文件中
定义任意数量的函数。而在 AS3 中,你在一个文件中只能定义一个函数,并且该函数的名称必
须与文件的名称相匹配。例如,如果你定义的函数的名称为 doSomeMath(),则你必须在一个名
称为 doSomeMath.as 的文件中创建该函数。在定义函数时,你可以使用类包声明(package
declaration)(你将在下一章节学习与包相关的内容)。因此当你希望创建大量工具函数,如果
你不希望在大量文件中编写这些代码,则你可以创建一个单一类然后将它们定义为静态方法。



OOP:类和接口
现在是讨论 PHP 和 AS3 的面向对象编程(Object Oriented Programming )功能的时候了。在
PHP 中,你可以编写面向对象或程序化的代码;而 AS3 是面向对象的语言。

让我们从简单 PHP 类开始来看看语法的不同点(记住我使用 PHP 5.3 作为编程参考语言):

  1: namespace orgcorlan {

  2:

  3:     class SimpleClass {

  4:

  5:          public $public = 'Public';

  6:          protected $protected = 'Protected';
7:         private $private = 'Private';

  8:

  9:         function SimpleClass() {

 10:

 11:         }

 12:         // Redefine the parent method

 13:         function displayVar()

 14:         {

 15:

 16:         }

 17:     }

 18: }

 19:

 20: //use the class like this

 21: require_once('flassFile.php');

 22: $obj = new orgcorlanSimpleClass();

 23: $obj->displayVar();




在 AS3 中,相同的类编写如下:

  1: package org.corlan {

  2:

  3:     public class SimpleClass {

  4:

  5:         public var _public:String = "Public";

  6:         protected var _protected:String = "Protected";

  7:         private var _private:String = "Private";

  8:

  9:         function SimpleClass() {

 10:
11:              }

12:

13:              // Redefine the parent method

14:              public function displayVar():void

15:              {

16:

17:              }

18:      }

19:

20: }

21:

22: //you use the class like this:

23: import org.corlan.SimpleClass;

24:

25: var object:SimpleClass = new SimpleClass();

26: object.displayVar();


下面是它们的主要差异:

       对存储类的文件进行命名

             o       在 PHP 中,你可以在一个文件中定义一个类,而该文件可以以任意方式命名

             o       在 AS3 中,文件的名称必须与类的名称相同 (如果类的名称为 SimpleClass,
                     则文件的名称必须为 SimpleClass.as)



       命名空间 vs 类包

             o       在 PHP 中,你可以使用命名空间以避免类之间的名称冲突

             o       在 AS3 中,你可以使用类包;然而,例如,当你在 org.corlan 类包中声明一个
                     类时,这意味着该类将会包含于 Flex 源文件夹的 org/corlan 文件夹中。该包名
                     可以转变为一个文件夹结构。与类访问修饰符( class access-modifier)一起使
                     用的类包能够将该类隐藏至项目之外的类中(后面将会详细讨论)。



       要求/包含 vs. 导入
o   在 PHP 中,通常你可以使用 require_once 函数包含定义类的文件。从 PHP 5 开
             始,你将能够定义一个__autoload() 函数,并且在该函数中包含 require_once 或
             include_once,而不需在每个文件的顶部编写一个要求的文件的列表 。

         o   在 AS3 中,你可以使用导入语句来包含期望的类。然而,如果你希望从类包
             org.corlan 中包含所有类,你可以使用一个通配符编写该导入语句:import
             org.corlan.*。另一个不同之处是 AS3 编译器只编译那些在你的代码中实际使用
             的类 (即只有在特定类的一个实例被实际创建的情形下) 。



     调用方法/实例成员:

         o   在 PHP 中,你可以使用 “->” 运算符

         o   在 AS3 中,你可以使用“.” (dot) 运算符



现在,让我们来讨论类/方法/成员修饰符。

我将从类修饰符开始讨论:

     PHP 具有 final 和 abstract 类修饰符;而 public 是隐式类修饰符,在 PHP 中,所有类均
      为 public。

     AS3 具有 public、internal、final 和 dynamic 类修饰符。如果你没有指定任何访问修饰符
      (public 或 internal),则该类默认为 internal,其含义为该类只能被来自相同类包的类
      访问。public 和 final 与 PHP 具有相同的含义。abstract 在 AS3 中不存在,但你可以使
      用接口克服这一限制。Dynamic 标示相应的类通过修改现有成员或添加新的成员能够在
      运行时进行更改。

类特性(class property)修饰符:

     PHP 具有 public、private、protected 和 static 修饰符。

     AS3 具有 PHP 修饰符加上 internal 修饰符。Internal 可用于使得特性(property)只能在
      相同类包的内部才是可用的。当没有指定修饰符时,可以使用 internal 修饰符。

类方法(class pmethod)修饰符:

     PHP 具有 public、private、protected、static、final 和 abstract 修饰符。

     AS3 具有 public、private、protected、static、final、internal 和 override 修饰符。abstract
      在 AS3 中不存在;Internal 可以使得方法只能在相同类包的内部的代码中才是可用的。

在 AS3 中,你可以使用函数闭包实现的每一件事均可以使用类函数实现。
PHP 的构造器可以标示为 private,你可以定义一个具有与类名称相同的构造器,或你可以使用
特定的方法__construct()和__destruct()。在 AS3 中,构造器总是具有 public 修饰符并且必须具有
与类相同的名称。如果没有提供任何修饰符,则 AS3 将为你在场景之后创建一个修饰符。

静态成员或静态方法是可以访问的:

        在 PHP 中,使用 ClassName::propertyName。

        在 AS3 中,使用 ClassName.propertyName。然而,在相同类的内部,你可以省略该类
         名称。

  1: package org.corlan {

  2:

  3:      public class Foo {

  4:

  5:          private static myVar:String;

  6:

  7:          function Foo() {

  8:              Foo.myVar = "value 1";

  9:              myVar = "value 2";

 10:          }

 11:

 12:      }

 13: }


这里:

        在 PHP 中,你可以使用特别的类变量$this 来指向在相同类中定义的类成员(变量/方
         法): $this->myVar = 22。

        在 AS3 中,你可以使用相同的 this:this.myVar = 22;然而,你可以忽略 this, 然后仅
         使用 myVar = 22 即可。

在 AS3 中,只有一个类能够在类包的内部进行声明(一个 this 类可以给出该文件的名称)。然
而,在类包声明的外部,你可以声明任意数量的类:

  1: package org.corlan {

  2:

  3:      public class Foo {

  4:
5:         private static var instance:Foo;

  6:

  7:         function Foo(object:Bar) {

  8:

  9:         }

 10:

 11:         static public getInstance():Foo {

 12:             if (Foo.instance == null) {

 13:                 Foo.instance = new Foo(new Bar());

 14:             }

 15:             return Foo.instance;

 16:         }

 17:

 18: }

 19:

 20: class Bar {}


这将产生一个有趣的效果:所有在类包外部的文件中定义的类将只能在相同文件内部声明的代
码中使用。对于所有其它代码,这些类不存在。记住 AS3 的限制,即你不能声明该构造器为
private。因此,通过使用与该范例相似的方法,你可以确保只存在一个 Foo 类的实例。如果某
外部代码调用该构造器时,系统将抛出一个运行时异常,因为外部代码不能使用 Bar 的实例并
且该类对于外部代码是不可见的。



继承
在 AS3 中进行类的扩展与在 PHP 中非常相似。你可以使用相同的 extends 关键词后面跟随你希
望扩展的类的名称。覆盖(Overriding)功能与 PHP 相同,有一点不同之处是你必须将 override
关键词添加至方法签名。AS3 不支持重载(Overloading)功能(你不能拥有两个或更多具有相
同名称的方法)。

在 PHP 中,你可以使用语句 parent::memberName 访问父成员;而在 AS3 中,你可以使用语句
super.memberName 访问父成员。当执行一个类的构造器时,首先应该调用父构造器。甚至当你
没有从你的代码中显式调用父构造器时也会发生父构造器调用。因此,当你在构造器方法中编
写代码时,你不能在你的代码之后放置父构造器的调用语句。这样,你可以为父类的正确初始
化提供了机会,因此子类将不会使用没有设置的成员。你可以使用语句 super()调用父构造器。
让我们来看看这些工作原理,先看 PHP 代码,然后再看 AS3 代码。

  1: class SimpleClass {

  2:

  3:     function SimpleClass() {

  4:         echo('SimpleClass() called');

  5:     }

  6:

  7:     function __construct() {

  8:

  9:     }

 10:

 11:

 12:     function displayVar()

 13:     {

 14:         echo "SimpleClass classn";

 15:     }

 16: }

 17:

 18: class ExtendClass extends SimpleClass {

 19:

 20:     function ExtendClass() {

 21:         $myVar = 1;

 22:         parent::SimpleClass();

 23:         //or

 24:         parent::__construct();

 25:     }

 26:     // Redefine the parent method

 27:     function displayVar()
28:     {

  29:         echo "Extending classn";

  30:         parent::displayVar();

  31:     }

  32: }

   1: public class SimpleClass {

   2:

   3:     function SimpleClass() {

   4:         trace("SimpleClass() called");

   5:     }

   6:

   7:     public function displayVar():void

   8:     {

   9:         trace("SimpleClass class");

  10:     }

  11: }

  12:

  13: public class ExtendClass extends SimpleClass {

  14:

  15:     function ExtendClass() {

  16:         super(); //we have to call first the parent constructor, and only after we can

execute our code

  17:         var myVar:int = 1;

  18:     }

  19:

  20:     override public function displayVar():void {

  21:         trace("overrided displayVar()");

  22:         super.displayVar();

  23:     }
24: }


让我们看一下在 AS3 中类是如何初始化的。当一个类被例示时,首先其所有的特性
(property)将被初始化,其次在类级别定义的静态代码将被执行(这在 PHP 中是不能执行
的),最后构造器将被执行。下面是范例代码:

  1: public class Foo {

  2:

  3:         private var a:int = 0;

  4:         private static var os:String;

  5:         trace("initializer");

  6:

  7:         if (Capabilities.os == "LINUX")

  8:               os = "LINUX";

  9:         else

 10:               os = "other";

 11:

 12:         public function Foo(a:int=1) {

 13:               trace("foo() executed");

 14:         }

 15: }

 16:

 17: var foo1:Foo = new Foo();

 18: var foo2:Foo = new Foo();

 19: //produces this output in console:

 20: initializer

 21: foo() executed

 22: foo() executed


在 AS3 中,你可以使用函数的原型特性(property)创建函数闭包之外的对象(这与你在
JavaScript 中使用的函数来创建/扩展类的情况是相似的)。下面是一个简短范例代码:

  1: //we create a function

  2: function MyClass(value:String = "Mihai") {
3:     //we create a property

  4:     this.name = value;

  5: }

  6: //we use the special variable prototype of the function

  7: //to create another method

  8: MyClass.prototype.setName = function (value:String):void {

  9:     //we have access to the property defined on MyClass object

 10:     trace(this.name);

 11:     this.name = value;

 12:     trace(this.name);

 13: }

 14:

 15: //create an instance

 16: var myObject = new MyClass();

 17: //accesing the method created earlier

 18: myObject.setName("Joe");


在后面的章节中,我将更多地讨论 AS3 的动态功能。



Getters/setters
在任何 OOP 语言中,你通常会使用 getters/setters 来控制你希望向外部暴露的类特性
(property)。PHP 也不例外。然而,在 AS3 中,可以使用关键词 set 和 get 对类特性
(property)提供特别支持。下面是范例代码:

  1: public class Employee {

  2:

  3:     private var _salary:int = 0;

  4:     private var _income:int = 0;

  5:

  6:     function Employee() {

  7:

  8:     }
9:

 10:     public function set salary(value:int):void {

 11:         if (value > 0) {

 12:             this._salary = value;

 13:             this._income = this._salary * 12;

 14:         }

 15:     }

 16:

 17:     public function get salary():int {

 18:         return this._salary;

 19:     }

 20:

 21:     public function get income():int {

 22:         return this.income;

 23:     }

 24: }

 25:

 26: //using this class

 27: var emp:Employee = new Employee();

 28: emp.salary = 1000;

 29: trace(emp.income);

 30: //this raise an error, because the income property is read-only

 31: //for the outside code

 32: emp.income = 120;


通常,尽管我使用 setter 和 getter 替代_salary 字段 ,但我可以调用这些方法,好像它们就是字
段或特性(property)而不是函数:以 object.salary = 20 替代 object.salary(20)。如果你选择不对
setter 进行定义,你可以获得只读特性(property)。这就是我使用_income 特性(property)所
实现的功能。

除了使得代码简洁一些之外,该功能还使得编写可以被其它应用程序使用的 API 或类更为简
单。假设在我的范例中,我选择创建_salary 字段作为一个 public 成员。如果后来我决定需要验
证能够设置的值,则我必须添加一个 setter。在 PHP 中,这可能需要使用如 myObject.setSalary()
的语句。此时,任何使用该类的代码将会被破坏;因此,代码必须使用 setter 进行更新。

在 AS3 中,你可以利用定义为 public var salary:int 的特性(property)来启动该类,并且当你决
定需要一个 setter 时,你可以对该变量重新命名,然后添加 public function set salary() 方法。使
用该类的任何代码将不受这一变更的影响,因为它仍然使用相同的语句 objectInstance.salary =
10 来访问该特性(property)。

在 AS3 中,当使用这种式样的 setter 和 getter 时,有一个惯例是在变量名称前添加一个下划
线。



接口
在 PHP 和 AS3 中,接口的工作方式几乎相同。一个显著的差异是在 PHP 中,你可以定义方法
以及常量,而在 AS3 中,你只能定义方法。然而,你可以定义 setter/getter:

  1: public interface IEmployee {

  2:

  3:     public function set salary(value:int);

  4:     public function get salary():int;

  5:     public function get income():int;

  6: }


异常
正如在 PHP 中的那样,AS3 能够支持异常处理:

  1: try {

  2:

  3: } catch(e:Error) {

  4:

  5: } finally {

  6:

  7: }

  8:

  9: //throwing an exception

 10: throw new Error("Some error");
在 AS3 中,对于所有错误来说,Error 是顶级类。你可以创建自己的错误以扩展该类,或你可
以使用现有的子类。



对象类型的转换和测试
有时,你希望将一个对象强制转换为一种不同的类型,或希望检查对象类型。在 PHP 中,你可
以使用 instanceof 检查对象的类型,而在 AS3 中,你可以使用 is 检查对象的类型。为了进行类
型强制转换,在 AS3 中,你可以使用两种不同的语句。

  1: class A {};

  2:

  3: class B extends A {};

  4:

  5: var b:A = new B();

  6: //casting

  7: var c:B = b as B;

  8: //or

  9: var d:B = B(b);

 10:

 11: //checking the type of an variable

 12: if (b is A)

 13:    trace(true);

 14: if (b is B)

 15:    trace(true);




变量作用域
前面我们已经了解了变量、函数和类是如何在 Flex 和 AS 3 中工作的,现在是讨论变量作用域
的时候了。在 PHP 中,通常你具有两个作用域:全局(global)(在文件级别定义的变量)和
本地(local )(在函数内部定义的变量)。

在 Flex 中,共有 5 个作用域:函数体(function body)、实例方法体(instance method
body)、静态方法体( static method body)、类体(class body)和全局作用域(global
scope)。向这些作用域添加访问修饰符(public/private/protected/internal)使得事情比在 PHP 中
变得更为复杂。
作用域可以嵌套。在本例中包含的作用域的变量/函数/成员均可以被嵌套的变量/函数/成员使
用。例如,当你在另一个函数体的内部声明一个匿名函数时,在 AS3 中,所有在外部函数定义
的变量可以在嵌套函数的内部使用。在 PHP 中,你必须传递你希望使用的变量,或添加 use 语
句:

  1: //php code

  2: function a() {

  3:     $a = 1;

  4:     $b = 2;

  5:

  6:     function b() use ($a, $b) {

  7:

  8:     }

  9: }

 10:

 11: //AS3 code

 12: function a():void {

 13:     var a:int = 1;

 14:     var b:int = 2;

 15:

 16:     function b():void {

 17:         //variables a and b are available here

 18:     }

 19: }


当你在一个未命名类包的内部声明一个函数时,其将被放置在全局作用域之中并且其对所有代
码均为可用的。然而,尽管在一个类包之外声明的任何函数仍然位于全局作用域,但其只能对
来自相同文件对代码是可见的。



数组
在 AS3 中,数组与 PHP 的情况非常相似,仅有一处差异:在 AS3 中,一个数组仅具有数字下
标。如果你希望创建一个关联数组,你可以使用 Object 类。如果你希望创建一个 key 是对象
(而非字符串)的哈希图(hash map)时,你可以使用 Dictionary 类。你可以使用 Array 类创建
数组,也可以创建多维数组。对于 Object 和 Array ,你均可以使用文字定义。让我们来看看若
干范例:

  1: var myArray1:Array = new Array(1, 2, "some string");

  2: //creates an array with three elements: 0->1, 1->2, 3->some string

  3:

  4: //literal definition for an array

  5: var myArray2:Array = [1, 2, 3];

  6: //ading two more elements

  7: myArray2.push(4,5);

  8:

  9: //a hash map, similar to associative arrays in PHP

 10: var myMap:Object = new Object();

 11: myMap.name = "Flex";

 12: //literal definition of a map

 13: var myMap2:Object = {name:"Flex"};

 14:

 15: //using Dictionary class

 16: var dic:Dictionary = new Dictionary();

 17: var anObject:Object = new Object(); //creating the key

 18: dic[anObject] = "some value"; //adding a value to Dictionary


你具有添加元素或删除元素的所有期望的方法,包括 push、shift、pop、unshift 和 splice。
Concat 可以用于将数组添加至另一个数组。在前面的范例中,你可以看到我是如何使用 push
来添加另外两个元素至一个数组。

数组具有不固定的长度。其长度随着你添加更多元素而增加。在 PHP 中,你可以使用“[]” 在数
组的结束部分添加一个新的元素。AS3 具有相似的方法,该方法使用数组的 length 特性
(property )(你也能够使用 length 特性(property )来声明数组的长度)。

  1: var array:Array = new Array();

  2: array[array.length] = 1;//array has the values: 1

  3: array[array.length] = 23;//array has the values: 1, 23
你可以使用 delete 将数组的一个特定元素设置为 undefined:delete array[index]。这一操作将不
会缩短数组的长度。你可以使用 for() 语句并且利用其 length 特性(property )对数组进行循环
操作。如果你希望对一个 Object 进行循环操作(这可以用于创建与 PHP 关联数组相似的数
组),你可以使用 for – each (其工作方式与 PHP 中相同的构造器相似) 或 for – in 语句(在 动态
(Dynamic)章节将会更多地对其进行讨论 )。



命名空间
如果你希望寻找与 PHP 命名空间对等的 AS3 概念,你应该阅读类(Classes)章节关于类包的
内容,因为 AS3 类包与 PHP 命名空间是相似的。

在 ActionScript 中,命名空间具有不同的含义。让我们来看看命名空间可以用来干什么,然
后,我将给出若干范例:

    1.   防止命名冲突(你可以在相同的类中创建具有相同名称的多个方法,每个方法存储于
         不同的命名空间)

    2.   向自定义 visibility 设置标示跨框架/程序的变量和方法(例如,Flex 使用一个名称为
         mx_internal 的命名空间;使用该命名空间而不使用 private 或 protected 使得使用这些来
         自 Flex 框架的跨类包和类的方法成为可能。同时,开发人员将被警告这些方法或成员
         不一定能够被外部使用,因为它们可能会改变)

    3.   实现基于许可的类的访问控制功能

    4.   创建能够基于特定选择的命名空间来改变其行为的类

在详细讨论命名空间之前,我们应该注意到命名空间可以被 Flash Player 内部使用以实现访问修
饰符:public、protected、internal 和 private。

你可以使用语句 namespace identifier = URI 定义一个命名空间。当你声明变量/方法以及希望限
定一个成员或方法以便使用它时,你应该使用标识符。URI 通常是一个 URL ,该 URL 对于你
的应用程序来说必须是唯一的。它并不是必须存在的,并且在大多数情形下,你应该使用你的
域名。例如,我可以定义一个如下形式的命名空间:namespace online =
“http://corlan.org/apps/online”。

你可以在能够定义变量的任何位置定义命名空间:在类包定义的顶层(它在整个程序中均可
用),或在类级别(它只能在定义它的类中可用)。在函数级别,你只能使用在其它位置定义
的命名空间(你可能需要这样做以便限定一个在其它位置使用相同命名空间定义的变量;你需
要知道相应的 URI 以便进行限定)。

你可以通过在相应声明之前放置命名空间标识符,在一个给定的命名空间中声明一个方法或变
量。例如:mynamespace var a:int = 1。当你在一个命名空间中定义一个变量或方法时,系统不
允许你使用其它访问修饰符(例如 private )。
为了调用在一个命名空间定义的变量或方法,你可以使用命名修饰符运算符“::”。假设你在一
个名称为 online 的命名空间中定义了一个名称为 myMethod() 的方法,你就可以使用语句
objectInstance.online::myMethod() 访问该方法。对变量来说,情形也是相同。有时,你可能需要
使用那些利用命名空间名称限制的变量或方法。你可以在相应的作用域打开该命名空间并且摆
脱该命名修饰符运算符的限制。你可以使用 use namespace namespaceidentifier 指令实现这一目
的。例如:

 1: public function doSomething() {

 2:     use namespace online;

 3:     //call the method defined in that namespace:

 4:     myMethod();

 5: }


你可以传送命名空间,例如,你可以从一个方法中返回一个命名空间,以便允许该调用代码使
用它来限定一个方法或成员。

现在,让我们来创建两个命名空间,它们可以用于在运行时改变类的行为。首先,我将定义这
两个命名空间(我将为每个命名空间提供一个文件):

 1: // ActionScript file online.as

 2: package org.corlan {

 3:     public namespace online = "http://corlan.org/apps/online";

 4: }

 1: // ActionScript file offline.as

 2: package org.corlan {

 3:     public namespace offline = "http://corlan.org/apps/offline";

 4: }


接下来,我将使用这两个命名空间创建一个能够存储一个对象的类。根据其链接状态,该类可
以在本地存储该对象(例如,使用本地存储设备),或以远端方式在服务器上存储该对象(使
用 REST 服务)。当某些代码需要使用该类时,有趣的部分将会出现。该调用的代码完全不关
心该方法,它只希望将该对象存储起来。

通过使用这两个命名空间,我将创建一个类,该类具有两个名称均为 save()的方法,每个方法
定义于其中一个命名空间。下一步,我将创建一个私有变量,该变量存储了当前的命名空间,
根据因特网连接的状态可以使用该命名空间。调用程序可以使用 getter 访问当前命名空间,并
且使用它来调用 save() 方法。再一次强调一下,调用程序不知道所有的这些 internal,而且不知
道这些命名空间,它也不关心这些命名空间。让我们看一下 PersistObject 代码:

 1: package org.corlan {
2:   import flash.events.Event;

 3:

 4:   public class PersistObject {

 5:

 6:       private var _mode:Namespace = offline;

 7:

 8:       public function PersistObject() {

 9:

10:       }

11:

12:       online function save(object:Object):void {

13:           //save the object back to server

14:           trace("online");

15:       }

16:

17:       offline function save(object:Object):void {

18:           //save the object locally

19:           trace("offline");

20:       }

21:

22:       private function connectivityChanged(e:Event):void {

23:           //here the mode can be changed from offline to online

24:           //and vice-versa

25:       }

26:

27:       public function get mode():Namespace {

28:           return this._mode;

29:       }

30:   }
31: }


下面的代码片段使用了该类。该代码段非常简单,并且行内的注释给出了说明。

  1: //creating an object that we want to be stored

  2: var object:Object = {book:"Ulysses", author:"James Joyce"};

  3: //create an instance of PersitObject

  4: var persistenceObject:PersistObject = new PersistObject();

  5: //get the current namespace

  6: var currentMode:Namespace = persistenceObject.mode;

  7: //use the namespace we retrieved to qualify the save method()

  8: persistenceObject.currentMode::save(object);




命名空间可访问性
你可以使用与变量或方法相同的访问修饰符:public, internal, protected 和 private (对于在类包级
别定义的命名空间,你可以只使用 public 和 internal)。将这一点与命名空间定义的位置结合起
来,你将对程序中命名空间的可见性具有很强的控制能力。



与 XML 的配合
在 PHP 中,通过本机函数或附加扩展对 XML 提供了大量支持功能。在 AS3 中,本机有两个类
可以表示 XML:XML 和 XMLList。AS3 能够基于 W3C DOM (你可以使用像 children()、
appendChild()、parent()、 insertChildBefore() 等方法) 实现 XML 类。当你利用 XML 进行编程
时,你应该了解如何使用 E4X。E4X (ECMAScript-for-XML) 是 ECMA-262 语言的一种扩展,
该扩展是通过 AS3 实现的。你可以使用 XML 来表示一个 XML 文档。即使在只有一个子类的
情形下,任何来自该文档的节点都将包含于一个 XMLList。

你可以使用下列任何方法创建一个 XML 对象:

   1.    使用文字形式编写 XML。

   2.    创建一个 XML 实例,然后从一个外部文件导入该 XML 实例。

   3.    创建一个 XML 实例,然后使用点记法(dot notation)以便添加/改变相应的结构:

  1: var author:XML = <author/>;

  2: author.@id = 1; //setting an attribute called id and its value

  3: //adding two child nodes to author:

  4: author.name = "Mihai Corlan";
5: author.article = "Flex for PHP developers";

  6:

  7: //this code is equivalent with:

  8: var author:XML = <author id="1">

  9: <name>Mihai Corlan</name>

 10: <article>Flex for PHP developers</article>

 11: </author>;


通过使用 E4X,你可以根据基于节点名称或属性值的创建条件很容易地找到节点。你可以使用
递减运算符 “..” 查询具有给定名称的所有节点(例如,为了查询所有程序节点,你可以使用语
句:programs..program)。你可以使用“@” 运算符 (例如, programs..program.(@id==2))创建
基于属性的条件。最后,通过使用点符号,你可以在节点之间浏览(应该记住即使在只有一个
子类的情形下,任何子类均被看作一个 XMLList)。下面你将看到使用 E4X 与 XML 配合的范
例:

  1: var programs:XML = <root>

  2:    <program id="1">

  3:            <name>Flex</name>

  4:    </program>

  5:    <program id="2">

  6:            <name>ActionScript 3</name>

  7:    </program>

  8:    <program id="3">

  9:            <name>AJAX</name>

 10:    </program>

 11: </root>;

 12:

 13: //retrieving the second program node and printing its name

 14: trace(programs.program[2].name[0]);

 15: //retrieving all the program nodes:

 16: var list:XMLList = programs..program;

 17: //retrieving all the program nodes that have an id attribute equal to 2
18: var list:XMLList = pograms..program.(@id==2);




动态 ActionScript
还记得 AS3 的定义吗?在该定义中,我给出了 AS3 是一种动态脚本语言的陈述。让我们更进一
步地讨论该功能。动态表示通过添加或删除方法或成员可以在运行时修改一个对象。系统能够
将新的方法添加至类的本身(并且任何由该类创建的对象将具有这些方法)。你甚至可以从头
创建新类(使用 protoype 特性(property))。AS3 具有内置的动态对象,例如 Object,而 Flex
具有另一个动态对象例子:ObjectProx。

如果你想知道为什么该功能首先出现,其答案是非常简单的:ActionScript 的早期版本不具有
AS3 今天提供的所有功能和 OOP。我必须说明,以我的经验来看,没有多少开发人员使用 AS3
的动态功能。这里有下面几个原因。首先,动态成员的访问速度要慢于固定成员。其次,你的
代码更易于出现软件缺陷(例如,没有编译时间错误检查)。

你可以不局限于使用内置类;你能够在类定义中使用 dynamic 修饰符创建动态对象:

  1: dynamic public MyDynamicObject {

  2:

  3: }


现在,通过使用你刚才定义的类,你可以在运行时添加成员(记住所有动态实例变量均为
untyped 和 public):

  1: var a:MyDynamicObject = new MyDynamicObject();

  2: a.author = "Mihai Corlan";


你可以使用 for-each-in 循环语句将一个动态类的所有成员遍历一次。下面是如何从前面的范例
中显示成员的代码:

  1: for each (var element:* in a) {

  2:     trace(element); //displays Mihai Corlan

  3: }


如果你希望获得成员名称而不是其值,你可以使用 for-in 循环语句:

  1: for (var memberName:* in a) {

  2:     trace(memberName); //outputs author

  3:     trace(a[memberName]); //outputs Mihai Corlan

  4: }
Flex 是异步的
到目前为止,我们已经讨论了许多 Flex 功能,并且其中大部分功能与其 PHP 的对等部分非常
相似。但是,Flex 的异步特性与 PHP 相比具有相当的差异。停止与之对抗并且顺其自然,了解
这一点非常重要。

“Flex 是异步的”这句话的含义是什么?假设你创建一个 Flex 应用程序,并且在该应用程序载入
浏览器之后,用户可以选择从另一个站点下载图片。你也许使用一个 URLLoader 类来实现这一
任务。当你执行 load() 方法时,在代码的下一行,你将不会拥有相应数据。在 load() 调用等待
相应数据已经载入之后,脚本不会暂停。取而代之的是脚本的执行将被恢复。作为一个程序
员,你可以使用内置的 AS3 事件系统处理这一异步特性。如果你熟悉 AJAX 编程,这与你在执
行一个 AJAX 调用时所做的事情相似:你提供一个回调函数,并且当数据到达时,该回调函数
将被调用并且你可以访问相应的下载数据。

回到 ULRLoader 范例,你可以为 result 事件添加一个事件侦听器。这是一个函数,当数据载入
之后,它将被调用。

  1: function loadPic():void {

  2:     var loader:URLLoader = new URLLoader();

  3:     loader.dataFormat = URLLoaderDataFormat.BINARY;

  4:     //adding the event handlers or listeners

  5:     loader.addEventListener(EventComplete, picLoaded);

  6:     loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, picError);

  7:     //starting the loading

  8:     loader.load(new URLRequest("http://some_url"));

  9: }

 10:

 11: //event handler for

 12: function picLoaded(event:Event):void {

 13:     //get the data from the loader object

 14:     //use the target property to get the loader object

 15:     (event.target as URLLoader).data;

 16: }

 17:

 18: //event handler for the error event
19: function picError(event:IOErrorEvent):void {

 20:     //displays the error id in a pop-up windonw

 21:     Alert.show(event.errorID);

 22: }


我从上面代码得出的功能概述是:别调用我们,我们将调用你们!

正如我在前面所述的那样,AS3 具有内置的事件系统。所有事件的顶级类是 Event。所有异步
工作的对象均具有 addEventListner() 方法,并且前面两个自变量为事件类型,以及在事件发生
时被调用的函数的名称。你可以认为只有处理检索的远端数据的对象才遵从该事件模型。实际
的情况并非如此;所有可见的组件或对象也具有各种事件。例如,每个 Flex 应用程序具有一个
creationComplete 事件。当所有应用程序要求的组件被处理并且在屏幕上绘制之后,该事件将被
触发。

尽管你可能感觉这样的代码不如 PHP 的代码简单易懂,但对于在 Flex(以及 Flash Player)中
随处可见的异步调用来说,这里具有一个恰当的理由:Flex 是一种客户端侧技术。例如,如果
所有调用均为同步调用,则应用程序的用户界面将会停止对涉及下载数据的调用的响应。而用
户非常厌恶不能对用户界面及时响应。

你可以删除一些事件,甚至能够改变其默认行为。如果你愿意,我将让你自己研究这些详细内
容。从现在开始,你应该对什么是事件和事件侦听器具有相当清晰的理解。




数据绑定、元数据标签和反射
数据绑定是另一个能够使得开发人员的生活更为轻松的 Flex 功能,并且同时能够减少代码的行
数。数据绑定是一种能够将数据模型与视图进行绑定的很好方法,并且能够自动更新视图以反
映任何数据模型的变化。

因为 Flex 可以用于创建应用程序的用户界面,因此 Flex 组件通常是以显示大量数据的方式结束
的。当数据被修改时,甚至在实时修改的情形下,通常,人们希望显示最新的而不是老旧的数
据。通过使用数据绑定功能,你能够轻松地实现这一目标。数据绑定可以将一个对象的特性
(property)(称为源)与另一个对象的特性(property)(称为目的地)进行链接,因此,每
当源改变时,相应的目的地将自动更新。

Flex 4 支持双向绑定功能(实际上 Flex 3 也支持该功能,但你需要在第二步对其进行声明),
这意味着绑定功能在另一个方向也能起作用:即当目的地被更新时,新的值将被复制到相应的
源。当你具有一个数据模型和一个表单时,这是非常有用的。你可以将数据模型与表单进行绑
定,然后当用户改变表单中的值时,双向数据绑定功能将会利用表单的值来更新数据模型。现
在,让我们来看看一些代码:

  1: <?xml version="1.0" encoding="utf-8"?>
2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal">

  3:    <mx:Script>

  4:         <![CDATA[

  5:

  6:               [Bindable]

  7:               private var labelValue:String = "Hello World!";

  8:

  9:               private function add():void {

 10:                   labelValue += "!";

 11:               }

 12:         ]]>

 13:    </mx:Script>

 14:    <mx:Label id="myLabel" text="{labelValue}"/>

 15:    <mx:Button label="Add a !" click="add()"/>

 16: </mx:Application>


labelValue 变量的 Bindable 元数据可以将其标示为数据绑定的源。下一步,我对 Label 的文本属
性使用了“{}” 符号以便将该特性(property )标示为该绑定的目的地。在设置绑定功能之后,
每当变量 labelValue 被改变时,标签将更新其视图以反映相应的改变。我可以针对许多标签或
文本输入使用相同的变量,而且他们都能够被更新以反映新的值。

这里也存在一个具有相同功能的 MXML 语句:<mx:Binding source=”labelValue”
destination=”myLabel.text”/>。如果你希望将该数据与一个可编辑的控件(例如,一种文本输
入)进行绑定,然后复制该值到该源,那么在 Flex 4 中,你可以使用“@” 运算符现实双向绑定
功能:

  1: <s:TextInput id="txt" text="@{labelValue}"/>


之后,如果你希望使用 Binding 标签,则你可以将属性 twoWay 设置为 true(再一次声明,这只
能适用于 Flex 4):

  1: <mx:Binding source="labelValue" destination="myTextBox.text" twoWay="true"/>


为了实现数据绑定功能,Flex 在编译时间添加了胶水代码(glue code )(记住数据绑定不是
Flash Player 或 AS3 的功能),这样做的美妙之处是你不需要自己编写该代码。

尽管数据绑定功能为数据模型与视图的绑定提供了一种简单易懂的方法,但是,如果你具有大
量的变量绑定,并且它们每秒更新数百次,则会对性能产生影响。对于这样的变量,没有必要
对用户界面进行如此频繁的更新,因为对浏览器自己执行的每秒帧数(大约每秒 50 帧)有相应
的限制。因此,试图每秒实时显示数百次变更是毫无意义的。

另一个需要记住的事情是并不是所有的对象均为可绑定的。例如,Object 和 Array 都不是可绑
定的,因此,你应该使用 ObjectProxie 和 ArrayCollection。当你创建类以便为数据建立模型
时,如果你希望该类的所有成员均为可绑定的,则你应该将 Bindable 元数据放置在类级别之
上,而不是为每个特性(property)添加 Bindable 元数据:

  1: package org.corlan {

  2:

  3:     [Bindable]

  4:     public class VOAuthor {

  5:

  6:         public var id_aut:int;

  7:         public var fname_aut:String;

  8:         public var lname_aut:String;

  9:     }

 10: }


现在,让我们讨论一下元数据标签(有时称为注解)。你已经看到了以 Bindable 元数据标签的
形式出现的元数据标签。如需获得你能够在 Flex 中使用的元数据标签的完整列表,请点击这
里。在一些情形下,MXML 编译器可以使用元数据标签以便产生胶水代码(如在 Bindable 的
情形下),而在另一些情形下,你可以使用元数据标签来向 Flash Builder IDE 发送示意,或在
MXML 标签中创建特性(property)。这是 Event 元数据的情形。例如,假设我编写一个类,它
能够在载入一个电影时抛出一个事件。我可以使用 Event 元数据声明该事件的类型和名称。之
后,我可以使用 MovieLoader MXML 标签的 movieLoadedEvent 特性(property)来为该事件注
册事件侦听器。让我们看看该类的代码以及如何在 MXML 中使用该类。

  1: //class definition

  2: package org.corlan {

  3:     import flash.events.EventDispatcher;

  4:     import flash.events.IEventDispatcher;

  5:

  6:     [Event(name="movieLoadedEvent", type="flash.events.Event")]

  7:

  8:     public class MovieLoader extends EventDispatcher {
9:

 10:         public function MovieLoader(target:IEventDispatcher=null) {

 11:               super(target);

 12:         }

 13:

 14:     }

 15: }

  1: <?xml version="1.0" encoding="utf-8"?>

  2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"

  3:         xmlns:local="org.corlan.*" layout="horizontal">

  4:     <mx:Script>

  5:         <![CDATA[

  6:               private function movieLoadedListener(event:Event):void {

  7:                    //do something with it

  8:               }

  9:         ]]>

 10:     </mx:Script>

 11:

 12:     <local:MovieLoader id="loader" movieLoadedEvent="movieLoadedListener(event)"/>

 13: </mx:Application>


这里还有其它与元数据相关的有趣事情。如果你在编译器上设置一个标志(keep-as3-metadata
后面跟随一个标签的名称),则你可以添加你的自定义元数据标签,并且编译器将会把这些标
签放入字节代码(bytecode)中。之后,你可以在运行时使用这些标签。例如,点击这里,你
可以阅读到如何使用自定义元数据标签为在一个 AIR 应用程序中存储一个给定数据模型提供一
种方法(稍后将更多地讨论 Adobe AIR )。

现在,我们将讨论本节的最后一个话题:反射。为了能够使用自定义元数据,你必须依靠 AS3
反射 API。

在 PHP 中,存在一个完整的面向对象的反射 API 系列:其中包括 Reflection、
ReflectionFunction、ReflectionParameter、ReflectionMethod 等等。下面是一个在简单 PHP 类之
上使用 Reflection 类的范例:

  1: class SimpleClass {
2:

 3:         public $public = 'Public';

 4:         protected $protected = 'Protected';

 5:         private $private = 'Private';

 6:

 7:         private function SimpleClass() {

 8:             echo('SimpleClass() called');

 9:         }

10:

11:         private function __construct() {

12:

13:         }

14:

15:         function displayVar() {

16:             echo "SimpleClass classn";

17:         }

18: }

19:

20:

21: Reflection::export(new ReflectionClass('SimpleClass')); //this outputs:

22:

23: Class [ <user> class SimpleClass ] {

24:     @@ /Applications/MAMP/htdocs/_learning/classes.php 7-26

25:

26:     - Constants [0] {

27:     }

28:

29:     - Static properties [0] {

30:     }
31:

 32:     - Static methods [0] {

 33:     }

 34:

 35:     - Properties [3] {

 36:         Property [ <default> public $public ]

 37:         Property [ <default> protected $protected ]

 38:         Property [ <default> private $private ]

 39:     }

 40:

 41:     - Methods [3] {

 42:         Method [ <user> private method SimpleClass ] {

 43:             @@ /Applications/MAMP/htdocs/_learning/classes.php 13 - 15

 44:         }

 45:

 46:         Method [ <user, ctor> private method __construct ] {

 47:             @@ /Applications/MAMP/htdocs/_learning/classes.php 17 - 19

 48:         }

 49:

 50:         Method [ <user> public method displayVar ] {

 51:             @@ /Applications/MAMP/htdocs/_learning/classes.php 22 - 25

 52:         }

 53:     }

 54: }

 55:


在 AS3 中,可以用于反射的 flash.utils 类包具有 3 个函数:describeType()、
getDefintionByNameI() 和 getQualifiedSuperClassName()。下面是一个 describeType() 输出的范例
(该输出是一个 XML 对象):

  1: public class SimpleClass {

  2:
3:      public var _public:String = "Public";

   4:      protected var _protected:String = "Protected";

   5:      private var _private:String = "Private";

   6:

   7:      function SimpleClass() {

   8:          trace("SimpleClass() called");

   9:      }

  10:

  11:      public function displayVar():void

  12:      {

  13:          trace("SimpleClass class");

  14:      }

  15: }

  16:

  17: function reflect():void {

  18:      var s:SimpleClass = new SimpleClass();

  19:      var description:XML = describeType(s);

  20:      trace(description);

  21: }

  22:

  23: //the output:

  24: <type name="org.corlan::SimpleClass" base="Object" isDynamic="false" isFinal="false"

isStatic="false">

  25:     <extendsClass type="Object"/>

  26:     <method name="displayVar" declaredBy="org.corlan::SimpleClass" returnType="void"/>

  27:     <variable name="_public" type="String"/>

  28: </type>




我的数据在哪里?将它显示出来!
作为一个 PHP 开发人员,你可以使用非常直接的方法读取数据、解析数据并且将这些数据在屏
幕上显示出来。连接 MySQL 数据库是每一个 PHP 开发人员需要学会的第一件事情。实际上,
我非常怀疑你能够一直阅读通篇文章至此而没有先偷看这一章节。



Flex 怎么样呢?我不得不令你失望,因为你没有通向存储于数据库中的数据直接入口。不过,
我猜想这其中肯定有些好事,因为你可以继续编写 PHP 文件来读/写数据库中的数据,甚至在

编写 Flex 应用程序时也是如此     。为什么没有从数据库中读取数据的直接方法?因为有句老
话说得好:“你应该绝不相信客户端!”

假设客户端是一个知道如何连接 MySQL 服务器的 Flex 组件。你如何存储其信任状
(credential)才能使得其不容易被盗并且数据库的安全不受损害?为每个用户设置一个不同的
用户密码然后向他们发送该信息?这就是为什么使用客户端技术直接连接数据库服务器,而不
通过在中间使用应用程序服务器不是一个好主意的原因之一。

通常,在 Flex 应用程序中,你可以利用服务器侧的脚本来管理数据库。Flex 可以为你提供一种
调用服务器页面并且在 Flex 中返回相应的响应的方法。共有 3 种不同的连接服务器数据源的方
式:REST 式样服务、 web 服务和 Remoting (或 RPC)。




你可以利用 HTTPService 类来使用 REST 式样服务。当你需要发起一个请求时,你可以发送
POST 变量,并且其响应可以是 XML、JSON (这里有一个用于解析 JSON 的第三方库)或自
定义格式。

如果在服务器(SOAP/WSDL)上具有 Web 服务,你可以使用 WebService 类。

但最有趣的方法是 remoting (使用 RemoteObject 类)。为什么我认为它是最酷的方法,这里有
3 个原因:首先,通过使用 remoting,你可以通过调用任一 public 方法在你的服务器上充分利
用你拥有的 PHP 类。通常,在 Flex 侧,你可以使用 RemoteObject 的实例,好像其就是远端
PHP 类。其次,你可以将数据模型从 PHP 侧映射到 ActionScript 数据模型,并且使得其自动完
成转换。这是极为重要的,因为当你使用具有类型的对象时,你能够获得编译时间错误检查和
代码完成功能的益处。这意味着代码更易于阅读并且不易出现软件缺陷。第三,该方法的消息
格式-AMF3 (Action Message Format) 是二进制格式,该格式与 SOAP/XML/JSON 相比运行速度
更快而且占用空间更小,特别地,对于具有大量数据的应用程序更是如此。该格式本身是开放
的,而且所有的开发人员均可以阅读相关的白皮书并且能够实现使用该格式的程序。
AMF3 之所以运行速度较快,是因为它能够对数据进行编码。因为,如果在一个数据集合中具
有重复的相同字符串,则该字符串只需进行一次编码,而所有其它字符串的出现均为引用。如
果一个数字少于 4 个比特,则只使用要求的最少数量的字节。




Adobe 的 James Ward 已经创建一种很好的测试方法,该测试方法能够说明 remoting 和其它方法
之间的不同之处。

Flex 在本机能够支持 Remoting,但在服务器侧情况却是不同的。PHP 不能在本机支持 remoting
和 AMF3。这是为什么你需要一个服务器侧库来支持 PHP Web 服务器的 remoting 功能。共有 4
个可用的库,并且全部能够免费使用。我已经编写了关于如何使用这些库的指南:Zend AMF,
PHPAMF, WebORB for PHP, SabreAMF。点击这里,你可以阅读一篇对它们进行比较的文章。

因为本机数据类型能够自动转换(PHP 类型至 AS3 类型的转换以及相反方向的转换),因此你
必须关注来自一种语言的本机类型是如何转换为其它类型的。这里 是一个 AMFPHP 库中的数
据类型一致性的范例。




Flex 和 PHP 项目的用户授权
在 Flex 和 PHP 项目中用户授权是如何进行的呢?答案非常简单,与 PHP Web 站点相同,你可
以使用会话和某种方法来验证用户密码即可。

通常,当在 Flex 中执行一个调用时,会话 ID 将会被自动挂起。因此,如果之前已经对用户进
行授权,则将使用相同的会话。

点击这里,你将会获得关于该话题的更多信息。




建立 Flex 和 PHP 项目
令人欣慰的是,PHP 和 Flex 均为成熟技术,因此当需要使用工具时,你可以具有大量的选择。
我将在本章节中讨论其中一些工具。
Flex for php_developers_info_q
Flex for php_developers_info_q
Flex for php_developers_info_q
Flex for php_developers_info_q
Flex for php_developers_info_q

Contenu connexe

En vedette

Machine Learning for automated diagnosis of distributed ...AE
Machine Learning for automated diagnosis of distributed ...AEMachine Learning for automated diagnosis of distributed ...AE
Machine Learning for automated diagnosis of distributed ...AE
butest
 
Empleo de las principales maderas en colombia
Empleo de las principales maderas en colombiaEmpleo de las principales maderas en colombia
Empleo de las principales maderas en colombia
shiruy25
 
мультфильм
мультфильммультфильм
мультфильм
irina zikina
 
GoOpen 2010: Stefan Engseth
GoOpen 2010: Stefan EngsethGoOpen 2010: Stefan Engseth
GoOpen 2010: Stefan Engseth
Friprogsenteret
 
Presentació de Diana Pijuan
Presentació de Diana PijuanPresentació de Diana Pijuan
Presentació de Diana Pijuan
Diana
 
Mayank bhutoria curriculum vitae october 2008 Mayank Bhutoria ...
Mayank bhutoria curriculum vitae october 2008 Mayank Bhutoria ...Mayank bhutoria curriculum vitae october 2008 Mayank Bhutoria ...
Mayank bhutoria curriculum vitae october 2008 Mayank Bhutoria ...
butest
 
Ser Mujer Con Epilepsia
Ser Mujer Con EpilepsiaSer Mujer Con Epilepsia
Ser Mujer Con Epilepsia
guest59c58a4
 
EEL4851writeup.doc
EEL4851writeup.docEEL4851writeup.doc
EEL4851writeup.doc
butest
 
What s an Event ? How Ontologies and Linguistic Semantics ...
What s an Event ? How Ontologies and Linguistic Semantics ...What s an Event ? How Ontologies and Linguistic Semantics ...
What s an Event ? How Ontologies and Linguistic Semantics ...
butest
 
doc - University of Idaho
doc - University of Idahodoc - University of Idaho
doc - University of Idaho
butest
 
Ask yourself questions like these: What is the specific thesis ...
Ask yourself questions like these: What is the specific thesis ...Ask yourself questions like these: What is the specific thesis ...
Ask yourself questions like these: What is the specific thesis ...
butest
 
slides
slidesslides
slides
butest
 
COM623M1.doc.doc
COM623M1.doc.docCOM623M1.doc.doc
COM623M1.doc.doc
butest
 
Presentatie LinkedIn NL
Presentatie LinkedIn NLPresentatie LinkedIn NL
Presentatie LinkedIn NL
Ruth Heylen
 

En vedette (19)

Eltroncotallado2 1
Eltroncotallado2 1Eltroncotallado2 1
Eltroncotallado2 1
 
Machine Learning for automated diagnosis of distributed ...AE
Machine Learning for automated diagnosis of distributed ...AEMachine Learning for automated diagnosis of distributed ...AE
Machine Learning for automated diagnosis of distributed ...AE
 
Empleo de las principales maderas en colombia
Empleo de las principales maderas en colombiaEmpleo de las principales maderas en colombia
Empleo de las principales maderas en colombia
 
мультфильм
мультфильммультфильм
мультфильм
 
GoOpen 2010: Stefan Engseth
GoOpen 2010: Stefan EngsethGoOpen 2010: Stefan Engseth
GoOpen 2010: Stefan Engseth
 
Ignite @ Antù - Il brand, il consumatore, la community
Ignite @ Antù - Il brand, il consumatore, la communityIgnite @ Antù - Il brand, il consumatore, la community
Ignite @ Antù - Il brand, il consumatore, la community
 
Presentació de Diana Pijuan
Presentació de Diana PijuanPresentació de Diana Pijuan
Presentació de Diana Pijuan
 
WS1
WS1WS1
WS1
 
Mayank bhutoria curriculum vitae october 2008 Mayank Bhutoria ...
Mayank bhutoria curriculum vitae october 2008 Mayank Bhutoria ...Mayank bhutoria curriculum vitae october 2008 Mayank Bhutoria ...
Mayank bhutoria curriculum vitae october 2008 Mayank Bhutoria ...
 
Ser Mujer Con Epilepsia
Ser Mujer Con EpilepsiaSer Mujer Con Epilepsia
Ser Mujer Con Epilepsia
 
EEL4851writeup.doc
EEL4851writeup.docEEL4851writeup.doc
EEL4851writeup.doc
 
What s an Event ? How Ontologies and Linguistic Semantics ...
What s an Event ? How Ontologies and Linguistic Semantics ...What s an Event ? How Ontologies and Linguistic Semantics ...
What s an Event ? How Ontologies and Linguistic Semantics ...
 
doc - University of Idaho
doc - University of Idahodoc - University of Idaho
doc - University of Idaho
 
Ask yourself questions like these: What is the specific thesis ...
Ask yourself questions like these: What is the specific thesis ...Ask yourself questions like these: What is the specific thesis ...
Ask yourself questions like these: What is the specific thesis ...
 
slides
slidesslides
slides
 
Carybé
CarybéCarybé
Carybé
 
L'hiver en Russie
L'hiver en RussieL'hiver en Russie
L'hiver en Russie
 
COM623M1.doc.doc
COM623M1.doc.docCOM623M1.doc.doc
COM623M1.doc.doc
 
Presentatie LinkedIn NL
Presentatie LinkedIn NLPresentatie LinkedIn NL
Presentatie LinkedIn NL
 

Similaire à Flex for php_developers_info_q

Html5移动web开发指南
Html5移动web开发指南Html5移动web开发指南
Html5移动web开发指南
Alex Wong
 
X Fire开发指南
X Fire开发指南X Fire开发指南
X Fire开发指南
yiditushe
 
Jira 4.0 白皮书
Jira 4.0 白皮书Jira 4.0 白皮书
Jira 4.0 白皮书
YUCHENG HU
 
架构风格与基于网络的软件架构设计
架构风格与基于网络的软件架构设计架构风格与基于网络的软件架构设计
架构风格与基于网络的软件架构设计
hqx_0324
 
SAM5业务流程梳理建模手册
SAM5业务流程梳理建模手册SAM5业务流程梳理建模手册
SAM5业务流程梳理建模手册
BPC流程社区
 
Flex 3 Cookbook 中文版V1
Flex 3 Cookbook 中文版V1Flex 3 Cookbook 中文版V1
Flex 3 Cookbook 中文版V1
yiditushe
 
Java eye新闻月刊 -_2010年01月_-_总第23期
Java eye新闻月刊 -_2010年01月_-_总第23期Java eye新闻月刊 -_2010年01月_-_总第23期
Java eye新闻月刊 -_2010年01月_-_总第23期
JianXiong Ma
 
Struts+Spring+Hibernate整合教程
Struts+Spring+Hibernate整合教程Struts+Spring+Hibernate整合教程
Struts+Spring+Hibernate整合教程
yiditushe
 
Struts+Spring+Hibernate整合教程
Struts+Spring+Hibernate整合教程Struts+Spring+Hibernate整合教程
Struts+Spring+Hibernate整合教程
appollo0312
 
Docbook dev note
Docbook dev noteDocbook dev note
Docbook dev note
cri fan
 
Docbook dev note
Docbook dev noteDocbook dev note
Docbook dev note
cri fan
 
Build desktop app_by_xulrunner
Build desktop app_by_xulrunnerBuild desktop app_by_xulrunner
Build desktop app_by_xulrunner
Rack Lin
 

Similaire à Flex for php_developers_info_q (20)

Html5移动web开发指南
Html5移动web开发指南Html5移动web开发指南
Html5移动web开发指南
 
01 Flex Introduction
01 Flex Introduction01 Flex Introduction
01 Flex Introduction
 
01 Flex Introduction
01 Flex Introduction01 Flex Introduction
01 Flex Introduction
 
Java explore
Java exploreJava explore
Java explore
 
Les 3 ppt
Les 3 pptLes 3 ppt
Les 3 ppt
 
X Fire开发指南
X Fire开发指南X Fire开发指南
X Fire开发指南
 
Php可调试团队开发环境配置
Php可调试团队开发环境配置Php可调试团队开发环境配置
Php可调试团队开发环境配置
 
Php可调试团队开发环境配置
Php可调试团队开发环境配置Php可调试团队开发环境配置
Php可调试团队开发环境配置
 
Jira 4.0 白皮书
Jira 4.0 白皮书Jira 4.0 白皮书
Jira 4.0 白皮书
 
架构风格与基于网络的软件架构设计
架构风格与基于网络的软件架构设计架构风格与基于网络的软件架构设计
架构风格与基于网络的软件架构设计
 
SAM5业务流程梳理建模手册
SAM5业务流程梳理建模手册SAM5业务流程梳理建模手册
SAM5业务流程梳理建模手册
 
Flex 3 Cookbook 中文版V1
Flex 3 Cookbook 中文版V1Flex 3 Cookbook 中文版V1
Flex 3 Cookbook 中文版V1
 
Java eye新闻月刊 -_2010年01月_-_总第23期
Java eye新闻月刊 -_2010年01月_-_总第23期Java eye新闻月刊 -_2010年01月_-_总第23期
Java eye新闻月刊 -_2010年01月_-_总第23期
 
Struts+Spring+Hibernate整合教程
Struts+Spring+Hibernate整合教程Struts+Spring+Hibernate整合教程
Struts+Spring+Hibernate整合教程
 
Struts+Spring+Hibernate整合教程
Struts+Spring+Hibernate整合教程Struts+Spring+Hibernate整合教程
Struts+Spring+Hibernate整合教程
 
Linux运维趋势 第0期 运维自动化
Linux运维趋势 第0期 运维自动化Linux运维趋势 第0期 运维自动化
Linux运维趋势 第0期 运维自动化
 
Docbook dev note
Docbook dev noteDocbook dev note
Docbook dev note
 
Docbook dev note
Docbook dev noteDocbook dev note
Docbook dev note
 
互联网精准广告定向技术-by牛国柱
互联网精准广告定向技术-by牛国柱互联网精准广告定向技术-by牛国柱
互联网精准广告定向技术-by牛国柱
 
Build desktop app_by_xulrunner
Build desktop app_by_xulrunnerBuild desktop app_by_xulrunner
Build desktop app_by_xulrunner
 

Flex for php_developers_info_q

  • 1. Flex 入门指南——PHP 开发者 Mihai Corlan 欢迎访问 InfoQ 中文站 RIA 专区浏览更多 Flex、Flash 开发内容
  • 2. 言 从上个世纪 90 年代末开始,我一直从事与 Web 相关的技术,而且我接触的第一个服务器端技 术是 PHP。后来,我转向 ColdFusion 和 Java 的开发工作,但我始终认为自己是一个 PHP 开发 人员。当 AJAX 技术出现时,我开始与 Prototype 和 script.aculo.us 等架构打交道,并且着手创 建自己的架构。 2006 年底,我开始体验进行 Flex 开发。这有点类似速成学习班,因为我需要在大约 4-6 个星期 内为 FDS((Flex Data Services, 现在称为 LiveCycle Data Services)将要问世的版本创建一个演 示应用程序。尽管当时我是一个 Flex 和 FDS 的新手,但该项目进展顺利,而且我非常享受这 次开发以及学习过程。 然而,在享受的同时,我感觉到 Flex 的不同之处。我的意思是当我在进行 ColdFusion 或 Java Web 的开发工作时,我并没有觉得其与 PHP 相比有不同之处。这仅仅是一个寻找正确的 API 以 及适应特定语言的问题。后来,当我开始在 DHTML 之上进行 AJAX 开发时,我感觉也没有不 同之处。你仍然使用相同的技巧、利用服务器端语言来创建大多数网站,以及在网站各处插入 一些趣味画面(对于本案例来说,它们是一些 AJAX widgets)。 当我使用 Flex 创建我的第一个 Web 项目时,我的天啊,这是一个巨大的转变。客户端和服务 器之间的清晰分离(除了服务器侧的业务逻辑之外的客户端侧业务逻辑)、需要进行编译而不 是翻译的客户端侧技术、以及客户端的两种语言等,所有这些均需要用一种不同于传统 Web 开 发的思维方式进行思考。 这就是我写作本文的原因。我希望与你分享一些与 PHP 相关的 Flex 特定的技巧。同时,我还 希望通过将 Flex 与 PHP 进行比较引入 Flex 概念,当然它们的比较必须是有意义的。因此本文 的目标读者是:  希望学习更多关于 Flex 和 Action Script 3 而不只是通过简单定义能够提供的内容的 PHP 开发人员  已经进行 Flex 应用程序编码尝试并且希望更广更深地了解 Flex 的 PHP 开发人员 本文没有涉及的内容是什么?试图改变你或说服你让你相信 Flex 优于 X 或 Y 不是我的本意。 我坚信项目具有各种各样的类型,并且利用不同的工具能够完成这些项目。 另外,本文没有为 Flex 或 ActionScript 3 提供完整的文件资料。目前,市面上有几十本专著的 数百页资料论述该主题。关于 Flex 的文章也有成千上万篇。而我的意图是在将 Flex 概念与 PHP 类似概念进行关联是有意义的情形下,针对最重要的议题为你提供足够的信息。为了使得 本文更为实用,我对其结构进行适当的安排并且尽力避免对细节进行过多的赘述。在本文的结 尾部分,我提供了 Adobe AIR 的简介和一些附加参考资料,以便于你能够查阅与本主题相关的 更多详细信息。
  • 3. 最后需要说明的是,对于本文给出的大部分范例,我选择使用 Flex 3 进行编程。作出这样的选 择有如下几个原因:首先,在写作本文时,Flex 4 仍然是 beta 版本。其次,由于 Flex 4 主要是 Flex 3 的演化版本,因此这里涉及的大部分应用程序能够适用于 Flex4,只需进行少许更改即 可。在一些范例中,我将指出这些不同之处。对于 PHP 范例,我选择使用 PHP 5.3 作为编程参 考语言。前面已经给出说明,现在让我们来看看下面的本文目录,然后开始用功学习。 Mihai Corlan ——Adobe 平台技术经理
  • 4. 录 什么是 Flex? .......................................................................................................................... 5 Flex: 一个框架绑定的两种语言 .............................................................................. 5 为什么你需要关注 Flex.............................................................................................. 6 从瘦客户端向智能/富客户端演化.......................................................................... 7 MXML 语言简介.................................................................................................................... 8 MXML 和 ActionScript 3 之间的混合 .............................................................. 12 CSS 式样 ....................................................................................................................... 13 在运行时修改 MXML 代码 ................................................................................... 15 ActionScript 3 语言简介 ................................................................................................... 17 隔离语句........................................................................................................................ 17 数据类型、变量和常量 ........................................................................................... 17 函数和匿名函数(闭包) ...................................................................................... 22 OOP:类和接口......................................................................................................... 24 变量作用域 ................................................................................................................... 36 数组 ................................................................................................................................. 37 命名空间........................................................................................................................ 39 与 XML 的配合 .......................................................................................................... 42 动态 ActionScript ...................................................................................................... 44 Flex 是异步的 ....................................................................................................................... 45 数据绑定、元数据标签和反射 ...................................................................................... 46 我的数据在哪里?将它显示出来!............................................................................. 52 Flex 和 PHP 项目的用户授权 ........................................................................................ 54 建立 Flex 和 PHP 项目...................................................................................................... 54 Flex SDK 和文本编辑器 ......................................................................................... 55 Flex Builder / Flash Builder 和 Eclipse PDT / Zend Studio ..................... 55 调试 Flex 应用程序 ................................................................................................... 55 什么是 Adobe AIR.............................................................................................................. 56 下一步计划是什么? ......................................................................................................... 57 总结 ........................................................................................................................................... 58
  • 5. 什么是 Flex? 最简单的回答是:Flex 仅仅是创建 Flash 应用程序的另一种方法。Flash 应用程序是在 SWF 文件 中编译的,并且由 Flash Player 在浏览器中进行播放。为什么我们需要使用另一种方法创建 Flash 应用程序?传统的 Flash 应用程序是使用 Flash 制作工具创建的。如果你查看一下该工 具,你会发现它主要适用于设计人员。其中包括一个舞台(stage),一条时间轴线(timeline) 以及各种绘画工具等。 当你在开发应用程序并且追求开发效率时,你需要各种组件,你希望通过重用代码尽可能地提 高开发效率,最后但并不是最不重要的一点是,你需要一个新型的 IDE。 因此,一种修正的回答可能是:Flex 是一种能够帮助开发人员快速创建富因特网应用程序 (Rich Internet Application)的开源框架,这些应用程序能够在 Flash Player 中运行。在 2006 年 的今天,随着 Flex 2、Flash Player 9 和 ActionScript 3 的推出,该框架已经趋于定型。目前的版 本是 Flex 3,2010 初,其下一个版本 Flex 4 将要面世。 Flex: 一个框架绑定的两种语言 在 Flex 之下,你将发现下列语言和工具:  两种语言:MXML 和 ActionScript 3。Flex 提供两种语言以便创建 Flex 应用程序。在下 面的章节中,我将进一步地讨论每种语言。  一个富组件库  各种编译器和调试器  用于编译和调试 Flex 应用程序的各种命令行工具 由于 Flex 是一种开源框架,因此我极力推荐你访问该计划的主页 http://opensource.adobe.com/flex 并且下载相关的 SDK。你能够从组建库中查阅到所有组件的源 代码,你能够查询相关的开放程序缺陷和功能库(http://bugs.adobe.com/flex),以及查看各种 规范的 wiki 页面。 Flex 提供的部分效率改善应该归功于其海量组件库。该组件库包含了所有你能够想象的 UI 组件 (例如,各种输入框(input box)、面板(panel)、视窗(window)、滑动条(slider)、数据 网格(data grid)、组合框(combo box)、折叠显示(accordio)和 Tab 设置(tab set)等
  • 6. 等)。另外,该组件库还包含各种布局容器和表单元素。在下面的图中,你能够看到 Flex 3 可 以提供的各种 UI 组件的屏幕截图(点击可以放大)。 如果这些组件仍然不够使用,则你可以进入相应的源代码,扩展这些组件以创建你自己的组件 或从零开始创建新的组件。 为什么你需要关注 Flex 在深入探讨什么是 Flex 之前,让我们暂停一下,重温为什么你需要关注 Flex 的原因。 传统的 HTML Web 应用程序具有“请求-响应”架构。在浏览器发送一个请求之后,相应的服务 器回送一个页面,这样的周期不断重复。HTML 和 CSS 为呈现该信息提供了卓越的选择, 正 如可提出证据加以证明的那样,这是目前最佳的选择之一。然而,随着时间的推移,这种架构 不仅局限于静态呈现,而已经扩展至应用程序平台。利用脚本技术,我们尝试创建动态页面以 及设计服务器使得其能够对特定请求给出响应。更进一步地,通过添加 DHTML 和 AJAX ,我 们能够将新的气息带入由 Web 服务器支持的页面:用户能够与载入页面互动并且在无需刷新整 个页面的情形下改变相关的视图。 随着这些技术的演化,各种复杂的应用程序不断出现。一些 Web 应用程序已经开始复制许多桌 面应用程序的功能而且同时能够保持 Web 应用程序的便利性(只要有浏览器和因特网连接的地 方就能够使用 Web 应用程序)。因此,各种在线版本的电子制表软件和文本编辑器不断涌现。 然而,从可用性的角度来看,在线应用程序的用户友好界面要比桌面应用程序差。同时,如需 创建这些复杂的 Web 应用程序,你必须掌握许多技术(JavaScript、DHTML、CSS、AJAX 库 以及服务器端等技术 )的各种技巧,并且你必须具有处理不同浏览器之间差异的经验以及了解 他们是如何实现 HTML/CSS/JS 的。因此,2002 年,Macromedia 提出了术语 RIA(Rich Internet
  • 7. Applications)来描述一种结合了 Web 应用程序的优势和桌面应用程序的益处的新型应用程序。 能够实现这一新型应用程序的技术就是 Flash Player。 通常,如果你希望创建应用程序(而不仅仅是一个 Web 站点或 Web 页面),你可以使用 Flex 来实现。一些应用程序几乎不能使用 HTML/JavaScript 来创建,而另外一些应用程序很难跨浏 览器一致运行。Flash Player 能够提供最好的图形引擎,它已经安装于 98% 的具有因特网连接 的计算机,并且能够将声音和图像视为“一等公民”。它支持麦克风(microphone)和 Web 摄像 (webcam)功能、支持流媒体和数据推送(streaming and data pushing)服务、以及提供卓越的 字体排印(typography)功能,其支持的功能可以填满很长的清单。 请看看下面三个应用程序以便了解使用 Flex 能够出现什么样的奇迹:  SumoPaint 是一个免费使用的图像编辑应用程序;  Mindomo 是一个思维导图应用程序;  Times Reader 是一个源自《纽约时报》(The New York Times)的应用程序。 随着时间的推移,其他技术已经进入 RIA 领域。除了使得如 Gmail 或 Google Spreadsheets 等应 用程序成为现实的 AJAX 不断发展之外,今天,我们还能够看到源自 Microsoft 的 Silverlight 应 用程序以及源自 Sun 的 JavaFX 应用程序。 从瘦客户端向智能/富客户端演化 让我们回到浏览器以及 Web 应用程序是如何传送的。当浏览器发出一个请求,相应的服务器将 使用静态内容(HTML/CSS/JS 代码)和脚本(这些脚本可能查询数据库或调用其他脚本,但最 终他们会输出 HTML/CSS/JS)的组合来准备一个页面。该页面由浏览器载入并且显示出来。在 此,一个关键元素是,通常该页面(或响应)具有显示标记(presentation markup )以及烘焙至 相同消息的数据。 当应用程序的新状态需要呈现时,浏览器发出一个新的请求,之后相应的服务器将准备请求的 页面。而客户端“仅仅”显示该数据。 Flex 应用程序以不同的方式工作。服务器发送已编译过的 Flex 应用程序 (SWF 文件) ,该应用 程序能够在浏览器中使用 Flash Player 插件运行。通常,该 SWF 文件只能支持客户端侧的业务 逻辑。如果需要数据(例如来自数据库),则 Flex 应用程序能够发送请求以获得这些数据。服 务器只发送数据(数据的格式可以为 XML、JSON 或 AMF3),并且客户端能够知道如何显示 该数据。我们这里讨论的是面向服务的架构: Flex 应用程序实际上是客户端–一种能够使用由服务器提供的数据服务的客户端。该应用程序能 够在浏览器不刷新页面或不重新装载 SWF 文件的情形下变更状态。该应用程序是一种能够不 仅仅显示数据的客户端。因此,通过利用 Flex 和 Flash Player 能够创建几乎任何对象,这些对 象对于在 Web 上部署各种游戏、应用程序以及 widget 具有重要意义,而这些游戏、应用程序 以及 widget 能够与“古典”Web 应用程序以及其他应用程序进行集成。
  • 8. 到此为止,已经谈论太多的枯燥理论,让我们看看一些程序代码吧! MXML 语言简介 MXML 是一种陈述性的、基于 XML 的语言。在 Flex 应用程序中,你可以使用 MXML 语言快 速地创建应用程序的结构/外观。在 Flex 中,你使用 MXML 能够创建的应用程序,也可以使用 ActionScript 3 来创建。然而,反向操作不能成立。 如果你能够使用 ActionScript 3 来创建可以使用 MXML 完成的应用程序,那么为什么 MXML 会 首先出现?通常学习和理解利用 XML 语言描述的用户界面比利用命令式语言描述的用户界面 要简单得多。这样利用 XML 语言编写的用户界面将会具有较少的代码。另外,为陈述性语言 建立工具比为命令式语言也简单得多。下面是利用 MXML 实现的一个范例“Hello world!”。 1: <Label text="Hello World!" fontSize="14" color="red" x="100" y="50"/> 在这段代码中,我使用了一个名称为 Label 的 Flex 组件在屏幕上显示若干文本字符。我将文本 的属性设置为我期望的文本格式。另外,我希望能够对外观及该 Label 在屏幕上的位置进行 (少许)客户化处理。因此,我使用了属性 fontSize、color、x 和 y。我相信你会同意这是非常 易于理解和学习的范例。 现在,考察一下利用 ActionScript 3 实现的相同范例: 1: var myLabel = new Label(); 2: myLabel.text = "Hello World!"; 3: myLabel.setStyle("fontSize", "14"); 4: myLabel.setStyle("color", "red"); 5: myLabel.x = 100; 6: myLabel.y = 50; 7: addChild(myLabel); 我使用了 7 行代码来实现前面我仅用包含一个标记和若干属性的 MXML 实现的范例!现在, 可以设想一下在一个真正的应用程序中,你采用大量的控件,并且在不同的容器中进行分组。 那么,维护利用 MXML 编写的代码要比维护使用几百行 ActionScript 3 编写的代码更为简单。 尽管你能够使用 MXML 描述你的应用程序,但你不能使用 MXML 实现你的应用程序的业务逻 辑。而你可以利用 ActionScript 3 实现这一目的。 Flex 应用程序能够运行于 Flash Player,而 Flash Player 只能支持 ActionScript 2 和 ActionScript 3。这意味着你在应用程序中编写的任何 MXML 代码必须通过相应的 MXML 编译器转换成 ActionScript 3 代码。然后,该代码通过 ActionScript 编译器被转换成 Flash Player 支持的字节代 码(bytecode)(SWF 文件)。
  • 9. 因此,几乎每个 MXML 组件的后面均存在一个 ActionScript 3 类(实际上,有些 MXML 标记没 有相应的 ActionScript 类,例如 Script 和 Model)。在下面的范例中,这是一个源自 Label 类的 一个代码片段( snippet ): 1: public class Label extends UIComponent 2: implements IDataRenderer, IDropInListItemRenderer, 3: IListItemRenderer, IFontContextComponent 4: 5: { 6: /** 7: * Constructor. 8: */ 9: public function Label() 10: { 11: super(); 12: 13: // this is so the UITextField we contain can be read by a screen-reader 14: tabChildren = true; 15: } 16: 17: /** 18: * @private 19: * Flag that will block default data/listData behavior. 20: */ 21: private var textSet:Boolean; 22: 23: ... 24: } In any Flex application you have at least one MXML file, which is the main application. For example, here is the complete code for the “Hello World!” application:
  • 10. 在任何 Flex 应用程序中,你应该至少具有一个 MXML 文件,这是主应用程序。例如,下面是 “Hello World!” 应用程序的完整代码。 1: <?xml version="1.0" encoding="utf-8"?> 2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> 3: <mx:Label text="Hello World!" fontSize="14" color="red" x="100" y="50"/> 4: </mx:Application> 根节点必须总是 Application,而且这是定义命名空间的位置。在本范例中,我仅仅提供一个用 于 MXML 语言和 Flex 组件的命名空间:mx(上面的代码是使用 Flex 3 编写的。如果使用 Flex 4,则代码具有微小的差异,其中声明了多个命名空间)。 如果你编写自定义组件,则必须为其添加一个命名空间。例如,在下面的代码中,我声明了第 二个命名空间指向我所创建的所有组件(在本范例中,我使用了一个我自己创建的名称为 MyCustomLabel 的自定义 label 组件): 1: <?xml version="1.0" encoding="utf-8"?> 2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*"> 3: <mx:Label text="Hello"/> 4: <local:MyCustomLabel text="world!"/> 5: </mx:Application> 到目前为止,你也许想知道 Flex 应用程序是如何处理不同页面的。对于 HTML Web 站点,通 常不同状态是在不同页面实现的。而 Flex 应用程序与桌面应用程序非常相似。这意味着你只需 使用一个 MXML 文件,即可在该页面上显示应用程序的不同状态。Flex 能够提供许多手段来 实现这一目的,这些方法包括使用如折叠显示(Accordion)、Tab 设置浏览器(Tabsets navigator)和牌布局管理器(Card layout)的 Flex 组件以及 Flex 模块等。 你已经看到 MXML 代码能够用于定义应用程序的外观。但你也能够利用它并且通过扩展现有 Flex 组件创建自定义组件。让我们来看一个范例。假设在你的应用程序中具有若干表单,这些 表单具有两个按钮:Save 和 Cancel。观察一下该 MXML 自定义应用程序的代码(该代码是在 一个名称为 FormButtons.mxml 的文件中创建的。所有 MXML 文件必须使用 mxml 扩展名)。 1: <?xml version="1.0" encoding="utf-8"?> 2: <mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="150"> 3: <mx:Button id="saveButton" label="Save"/> 4: <mx:Button id="cancelButton" label="Cancel"/> 5: </mx:HBox>
  • 11. 当你创建自定义应用程序时,你能够选择需要扩展的任何组件(但你不能对 Application 进行扩 展)。我选择扩展 HBox (Horizontal Box),这是一个能够在相同行显示所有 children 的容器。在 该容器的内部,我添加了两个按钮,一个用于 Save,另一个用于 Cancel。我还为每个按钮设置 了 id 属性。你可以使用 id 属性值作为引用代码其他部分的对象的一种方式。这与在 ActionScript 代码中声明一个变量的方式是相同的。 现在,让我们看看你如何在一个 Flex 应用程序中使用该自定义组件: 1: <?xml version="1.0" encoding="utf-8"?> 2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*" layout="horizontal"> 3: <mx:TextInput width="150"/> 4: <local:FormButtons/> 5: </mx:Application> Below you can see how the application looks: 你也许会认为在 MXML 中你只能使用视觉 Flex 组件(即最终能够被显示的组件)。实际上, 这是不确切的。你可以使用表示数据的 MXML 标签(用于存储数据的对象)或操作数据的组 件(能够从服务器查询数据或向服务器发送数据的组件)。下面,你能够看到一个 generic 对象 组件的范例,该组件具有一个名称为 name 的特性(property): 1: <mx:Object id="myObj" name="Mihai Corlan"/> 正如我前面所述的那样,与 Flex 相伴的所有(几乎所有)Flex 组件均具有 ActionScript 类,该 类能够实现视觉外观(如果有的话)以及相应的逻辑。当你选择使用 ActionScript 而不是 MXML 创建一个自定义组件(不论其是否是视觉组件)时,你必须记住存在以下限制:在不带 自变量的情形下,该类的构造器(constructor)必须能够被调用(如果具有自变量,则这些自变 量应该具有默认值)。
  • 12. MXML 和 ActionScript 3 之间的混合 返回到自定义组件 FormButtons (具有两个按钮的组件),你也许注意到一个问题:如果你希望在 一个 Save 和 Cancel 标签不起作用的地方使用该组件将会怎样?你应该创建另一个带有你期望 的标签(例如 Show 和 Hide)的自定义组件吗?当然,这是一个选择,但这个组件不能缩放或 外观不太优雅!你所真正期望的是一个更为通用的组件,以及一种使用代码变更组件的方法。 这是为什么迟早你不得不在 MXML 代码中添加 ActionScript 代码。 在下面的范例中,我在组件的 MXML 代码中添加了 ActionScript 代码以定义两个存储了按钮使 用的标签的变量。注意,我使用了一个新的标签 Script,并且在该标签之中使用了 CDATA。这 是因为在 XML 文档之中,像>、<和& 等字符是非法的(如果它们没有换码)。另外,现在我 将不会把太多重点放在 ActionScript 代码上,但我将在后面的章节中更深入地讨论 ActionScript 代码。 1: <?xml version="1.0" encoding="utf-8"?> 2: <mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="150"> 3: <mx:Script> 4: <![CDATA[ 5: public var label1:String = "Save"; 6: public var label2:String = "Delete"; 7: ]]> 8: </mx:Script> 9: <mx:Button id="saveButton" label="{label1}"/> 10: <mx:Button id="cancelButton" label="{label2}"/> 11: </mx:HBox> 我定义的变量可以在使用该组件的 Flex 应用程序中设置。下面,让我们来看看在使用新的自定 义组件之后,变更的 Flex 应用程序代码的构成。 1: <?xml version="1.0" encoding="utf-8"?> 2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*" layout="horizontal"> 3: <mx:TextInput width="150"/> 4: <local:FormButtons label1="Show" label2="Hide"/> 5: </mx:Application> 注意,FormButtons 标签具有两个属性: label1 和 label2。这是为什么你能够在这些按钮上设置 期望显示的文本。并且这是你使用的机制以便将更多的行为添加至 MXML 组件(使用
  • 13. ActionScript 代码)。在真正的应用程序中,你可能希望将一个行为与每个按钮进行绑定,以便 当按下按钮时,就会产生相应的结果。你可以使用 ActionScript 代码编写通过按下按钮即可触 发的各种函数。 另外,还有一种在 MXML 至添加 ActionScript 代码的方法。你可以先创建一个 ActionScript 文 件(在本范例中,该文件的名称为 buttons.as),然后将该文件包含于 MXML 文件中。你可以 通过添加一个具有 source 属性的 Script 标签实现这一操作 ,而该属性指向该 ActionScript 文 件。下面是这一方法的代码。 1: // ActionScript file called buttons.as 2: public var label1:String = "Save"; 3: public var label2:String = "Delete"; 1: <?xml version="1.0" encoding="utf-8"?> 2: <!-- MXML component file called FormButtons.mxml a--> 3: <mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="150"> 4: <mx:Script source="buttons.as"/> 5: <mx:Button id="saveButton" label="{label1}"/> 6: <mx:Button id="cancelButton" label="{label2}"/> 7: </mx:HBox> 现在,让我们后退一小步,然后推测一下当 MXML 编译器解析 FormButtons.mxml 文件时会发 生什么情况。你已经知道所有代码将会转换成 ActionScript 代码。但对于我添加的现有 ActionScript 代码(两个变量)会发生什么情况呢?MXML 编译器将会把每个 MXML 文件编译 至一个 ActionScript 类。在这种情形下,我将获得一个名称为 FormButtons(因为这是该文件的 名称并且它可以用于该类的名称)的类,该类扩展了 HBox 组件(因为我选择了 HBox 作为该 组件的根节点)。该类中的所有 ActionScript 代码将会变成该类的成员:变量(例如本范例中 的变量)将会变成实例变量,并且函数将会变成实例方法。 CSS 式样 到目前为止,你也许想知道你是否能够改变视觉 Flex 组件的外观。Flex 组件具有类似 HTML CSS 的技术?答案是肯定的,Flex 支持 CSS。在 Flex 4 中,对 CSS 的支持已经扩展至允许不仅 可以基于类的名称而且可以基于 ID 进行式样定义,以支持伪选择符(pseudo-selector)(例
  • 14. 如,对于一个按钮来说,你应该具有下选择符(down selector)、上选择符(over selector)等 等)以及其他更多功能。 与在 HTML 中一样,式样可以在行中(在 MXML 代码内部)定义或在一个独立的文件中定 义。让我们先回到自定义组件 FormButtons, 然后设置若干式样。如果你选择在一个独立的文件 中定义试样,则必须使用一个 Style 标签并且将路径设置为 source 属性中的式样文件。 1: <?xml version="1.0" encoding="utf-8"?> 2: <!-- MXML component file called FormButtons.mxml a--> 3: <mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="150"> 4: <mx:Style> 5: .Button1 { 6: font-size: 14; 7: color: #990000; 8: } 9: </mx:Style> 10: <mx:Script source="buttons.as"/> 11: <mx:Button id="saveButton" styleName="Button1" label="{label1}"/> 12: <mx:Button id="cancelButton" label="{label2}"/> 13: </mx:HBox> 我创建了一个名称为 Button1 的 CSS 类,该 CSS 类定义了标签颜色以及字体大小。然后,我使 用第一个按钮的 styleName 属性将式样设置为第一个按钮。至此,该应用程序如下图所示:
  • 15. CSS 式样在运行时能够改变(在 Flex 应用程序载入浏览器之后),并且该应用程序的外观也会 立即随着改变。 在 Flex 4 中,Adobe 添加了名称为 MXML 用于图形的新语言,该语言添加了原语 (primitive)、效果(effect)、面具( mask) 和 2D 转换功能。你可以使用这些新的标签在 MXML 文件中创建皮肤(skin)类,然后你能够将该类设置为你期望对其进行皮肤粘贴的组 件。在下图中,你能够看到一串以 Flex 4 为皮肤的图像。左边给出了该串图像的默认状态,而 右边给出了该串图像的打开状态。你可以点击这里 观看处于运行状态的应用程序。 当你在关于 Flex 应用程序外观的自定义的文档中徘徊时,你也许能够理解术语“皮肤粘贴”的含 义。你可以进行图形皮肤粘贴(graphical skinning )或编程皮肤粘贴(programmatic skinning ) 以便改变相应的外观。点击这里 可以获得关于这方面问题的佳文。 在运行时修改 MXML 代码 有时候你希望在运行时变更 UI 组件。也许你希望根据你从服务器中检索到的数据来实时地建 立一个表单。同样,你也能使用 ActionScript 代码实现这一任务。任何视觉 Flex 组件均具有添 加一个新子类、移除一个新子类以及获取所有子类等方法。如果你愿意,你可以将这些方法与 在 HTML 中使用 JavaScript 改变 DOM 的方式进行比较。然而,它们之间存在差异:利用 JavaScript 你可以注入你从服务器检动态索到的 HTML 代码(通过一个 AJAX 调用)。但在 Flex 中,这是不可能,并且在 Flex 中不存在 eval() 函数。然而,在主应用程序载入之后,有方 法可以载入其它 Flex 应用程序或 Flex 模块。 当你了解一个组件的所有不同视图时,你能够使用 MXML States 来实现相同组件或应用程序的 不同状态。状态功能是 Flex 4 对比 Flex 3 的实现方式改善非常显著的地方,这使得这些状态更 加易于使用并且添加更多功能。在 Flex 4,状态的工作方式如下:
  • 16. 1. 你可以定义若干状态并且指定默认状态 2. 你能够指定在一个特定的组件应该出现在哪些状态中 3. 你可以指定在状态出现的位置每个状态的任何属性的独立值 假设你希望创建一个处理应用程序登录功能的组件。你希望使用该组件显示登录表格,并且在 登录成功之后,你希望显示退出按钮以及用户姓名。 下面是使用 Flex 4 创建的登录/退出组件: 1: <?xml version="1.0" encoding="utf-8"?> 2: <s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/halo"> 3: <s:states> 4: <s:State name="notlogged"/> 5: <s:State name="logged"/> 6: </s:states> 7: 8: <s:TextInput includeIn="notlogged" text="user name"/> 9: <s:TextInput includeIn="notlogged" text="password"/> 10: <s:Button includeIn="notlogged" label="Login" click="{currentState='logged'}"/> 11: 12: <mx:Label includeIn="logged" text="Current user: Mihai Corlan"/> 13: <s:Button includeIn="logged" label="Logout" click="{currentState='notlogged'}"/> 14: <s:layout> 15: <s:HorizontalLayout/> 16: </s:layout> 17: </s:Group> 上面的代码应该是很容易理解的。作为顶部容器,我使用一个具有设置为 HorizontalLayout 布 局的 Group 组件(这与用于上面范例 Flex 3 中的 Hbox 具有相同的效果)。我已经在该文件的 顶部为该组件定义了可用状态。接下来,我还定义了按钮、文本输入和标签。注意一下指定该 组件在什么状态下会出现的 includeIn 属性。另外,文件中还包含一个 excludeFrom 属性。如果 你希望在所有状态下定义一个按钮,则无需为这两个属性指定任何状态。最后,你可以看到我 为这两个按钮的点击属性指定了一个表达式。例如,表达式 click=”{currentState=’logged’}” 告 诉 Flex 当按钮被点击时,应该将该组件的状态改变为名称为 logged 的状态。
  • 17. 尽管我一直在讨论 MXML 语言,但我已经将越来越多的 ActionScript 代码加入了这些范例。这 是一个迹象:该到讨论第二种 Flex 语言 ActionScript 3 的时候了。 ActionScript 3 语言简介 ActionScript 3 是一种动态的面向对象的脚本语言,它是(或几乎是)一种类型安全的语言。 ActionScript 3 基于 ECMAScript 3 规范 (ECMA-262)。另外,其某些功能也是符合 ECMAScript 4 的相关建议。我已经发现采用下列方式对完全是 ActionScript 3 新手的开发人员解释该语言是 最容易的:ActionScript 很像 JavaScript 和 Java 的一个混合语言,并且其具有很强的个性。实际 上,JavaScript 是另一种基于 ECMAScript 规范的语言,因此,其与 ActionScript 自然而然地具 有许多共同点。 正如我前面所述的那样,Flash Player 能够运行两种语言:ActionScript 2 和 ActionScript 3。 Flash Player 在其内部使用两种不同的虚拟机(Virtual Machine)来协调这两种语言 (ActionScript 3 和 AVM2 Virtual Machine 是在 Flash Player 9 中推出的)。ActionScript 3 是由 核心语言(关键字和数据类型等 ) 以及 Flash Player API (该 API 使得开发人员能够通过显示列表 API( display list API)、3D API、绘画 API(drawing API)以及动画(Animation)等 API 使 用所有 Flash Player 功能)构成的。在本文中,我将侧重讨论核心语言。点击 这里 ,你可以获得 一篇关于 ActionScript 3 的入门佳文。 从现在开始,我将使用缩写“AS3” 替换 “ActionScript 3”。 隔离语句 在 PHP 语言中,你可以使用分号(;) 来隔离或结束一条语句。而在 AS3 语言中,你可以使用分 号(;) 或仅仅行尾符。但我必须说,当我看到不用分号编写的代码时,我的眼睛将不会出现喜悦 的目光。因此,我建议你使用与 PHP 使用的相同方法。 数据类型、变量和常量 PHP 具有下列数据类型:布尔(Boolean)、整数(integer)、浮点数( floating point number)、字符串( String)、数组(Array)、对象( Object)、资源( Resource)和 NULL。 对于 AS3 来说,我们具有下列数据类型:  顶级数据类型:布尔(Boolean)、整数(int)、单元(uint)、数( number)(与 PHP 的浮点数相同)、字符串( String)、Null (仅包含一个值:null)和 void (仅包含一 个值:undefined)
  • 18. 复杂数据类型:对象( Object)、数组(Array)、矢量(Vector )(以 Flash Player 10 开头)、字典(Dictionary)、位图(Bitmap)、字节数组(ByteArray)、日期 (Date)、XML、XMLList、函数(Function)、错误(Error)和 RegExp 等。 在 AS3 语言中,一个变量就是与实际值关联的一个标识符或指针。AS3 中的合法值可以是对象 (int 或 uint 是对象,Number 或 Date 也是对象)、null 和 undefined。null 和 undefined 均表示数 据缺失,但它们之间存在差别。当你声明一个变量并且你没有对其初始化时,并且如果变量的 类型不是 Boolean、int、uint 或 Number,则该变量具有值 null 。如果变量没有赋予数据类型并 且没有初始化,则该变量具有值 undefined。同时,当你拥有一个动态对象并且希望检查一个特 定的方法或特性(property)是否被定义时,你可以对 undefined 进行检查。 在 PHP 中,你可以按照下面的方式声明一个变量: 1: $anInteger = 12; 2: $isTrue = true; 3: $aString = "my string"; 4: //or 5: $aString = 'my string'; 在 AS3 中,你可以使用 var 关键词声明一个变量: 1: var anInteger:int = 12; 2: var isTrue:Boolean = true; 3: var aString:String = "my string"; 4: //In AS3 you can not use simple quotes for declaring a String 注意在该变量名称之后,我添加一个类型注解;例如,myVarName:Boolean (该类型是使用 “:” 声明的,后面紧跟相应的类型)。在 AS3 中,你可以使用类型注解,也可以不使用类型注解 (如果编译器设置为严格模式(strict mode ),则你必须使用类型注解)。 对于 PHP 来说,你不必声明变量的类型,因此,这一点也许显得奇怪,而且你可能希望坚持使 用不指定类型的方式编写程序。由于使用类型注解具有诱人的优点,我强烈推荐你使用类型注 解。首先,当你使用 IDE 编写代码时,对变量进行分类将使得你在编译时发现更多错误。例 如,设想具有一个单一 String 自变量的函数。如果你试图调用该函数,将一个 Object 作为自变 量进行传递,则 IDE 将提醒你这是错误。 如果不使用类型注解,你可能会遇到运行时错误,但只能在你或最终用户运行该应用程序时才 会发现,并且此时查明软件缺陷的根源将会非常困难。 坚持使用类型注解的第二个原因是,如果 AS3 编译器知道变量的特定类型,则其能够对应用程 序进行优化。
  • 19. 在 PHP 中,你能够利用每次赋值改变变量的类型: 1: $myVar = 12; //it is an int 2: $myVar = "now is a string"; 在 AS3 中,只有当你使用“*”声明变量为 untyped 时,你才能够完成相同当操作(使用严格模 式)。 1: var myVar:int = 12; 2: //this will raise an error and the application can not be compiled 3: myVar = "this is a string"; 4: 5: //declaring the variable untyped you can change the type with each assignment 6: var myVar2:* = 12; 7: myVar2 = "this is a string now"; 你可能注意到只有当声明变量时我才使用关键词 var。对于下一步赋值操作,你可以忽略 var 和 类型注解。 正如我前面所述的那样,在 AS3 中变量仅仅是实际值的指针。然而,当你将 int、uint、 Number、Boolean 或 String 变量赋值给另一个变量时,将会创建一个副本(对于将这些类型的 一个变量传递给一个函数时,情况也是相同的)。在 PHP 中,你可以使用 “&” 运算符通过引用 为原语类型进行变量赋值;当你为一个变量改变值时,其它变量将指向相同的改变值。 在 PHP 中,你使用“.” (dot)对字符串进行串接,而在 AS3 中,你可以使用“+” (plus)完成相同的 任务: 1: //in PHP 2: $space = " "; 3: $a = "this" . $space . "is!"; 4: 5: //in AS3 6: var space:String = " "; 7: var a:String = "this" + space + "is!"; 在 PHP 中,你可以在任何你期望的位置定义变量:例如在文件级、在函数中或在类中。在 Flex 应用程序中,变量只能在函数中或类级别中声明。
  • 20. 此外,在 PHP 中,你可以编写一段没有在函数中声明的过程化程序代码(procedural programming ): 1: <?php 2: 3: $a = 1; 4: for ($i=0; $i<100; $i++) { 5: $a += $i * $a; 6: } 7: 8: ?> 在 AS3 中,你不能利用函数之外的变量进行任何操作(尽管你可以在函数之外声明变量),但 有一个例外,我将在 Class 章节讨论它。因此,如果你试图运行下面的代码,你将在编译该应 用程序时出错。 1: <?xml version="1.0" encoding="utf-8"?> 2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> 3: <mx:Script> 4: <![CDATA[ 5: var a:int = 1; 6: for (var i:int = 0; i<100; i++) { //this raises an error 7: a += i * a; 8: } 9: ]]> 10: </mx:Script> 11: </mx:Application> 这是你为什么你可以通过重写该代码以便其能够正常运行: 1: <?xml version="1.0" encoding="utf-8"?> 2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> 3: <mx:Script> 4: <![CDATA[ 5: var a:int = 1;
  • 21. 6: 7: function calculations(a:int):int { 8: for (var i:int = 0; i<100; i++) { 9: a += i * a; 10: } 11: return a; 12: } 13: ]]> 14: </mx:Script> 15: </mx:Application> 在 PHP 中,可以按照下面方式声明和使用常量。 1: //constants 2: define("CONSTANT", "Hello"); 3: $myString = CONSTANT . ‘ world!’; 在 AS3 中,可以使用 const 关键词声明常量(使用大写字母命名常量是一个惯例): 1: static const HELLO:String = "Hello"; 2: var myString:String = HELLO + " world!"; 什么可以用于变量的名称呢?对于 PHP 和 AS3 来说,这一点是相似的:只要名称的第一个字 符为字母或在“_”之后跟随字母、数字或下划线,该名称即为合法名称。对于两种语言来说,下 面均是合法变量名称的范例:_1, _a1A, b。 在 PHP 中,通过了解其字符串名称,你可以使用该变量: 1: <?php 2: $myVar = 12; 3: $varName = 'myVar'; 4: echo($$varName); //print 12; 5: ?> 在 AS3 中,通过使用引用成员的动态方法(变量/方法),你可以获得相似的功能: 1: <?xml version="1.0" encoding="utf-8"?> 2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()">
  • 22. 3: <mx:Script> 4: <![CDATA[ 5: 6: var myVar:int = 12; 7: 8: function init():void { 9: var varName:String = "myVar"; 10: trace(this[varName]); //output 12 11: } 12: ]]> 13: </mx:Script> 14: 15: </mx:Application> 在该范例中,我使用了 this 来引用当前对象,但你可以对任何对象使用相同对技巧。当讨论动 态类时,我将用更多当篇幅来对此进行说明。 函数和匿名函数(闭包) 在 AS3 中,你可以利用函数实现你可以在 PHP 中实现的每一件事,甚至更多事情。首先,在 AS3 中,你可以定义自变量类型和返回类型(在 PHP 中,你只能从对象添加类型注解至方 法)。 1: function calculate(x:int=0, y:int=0):int { 2: return x + y; 3: } 4: //using the function 5: var result:int = calculate(1, 2); 6: 7: function calculateAverage(...arguments):Number { 8: var result:Number = 0; 9: for (var i:int=0; i<arguments.length; i++) { 10: result += arguments[i];
  • 23. 11: } 12: return result/arguments.length; 13: } 14: 15: //using the function 16: var result:Number = calculateAverage(1, 2, 3, 4, 5, 6); 你可以将… (rest) 运算符与显示自变量进行混合,只要你将… (rest) 运算符作为自变量列表的最 后一个元素放置即可:function foo(x:int, y:int, …arguments):Number {}。当你希望利用自变量中 的一个变量成员创建函数时,… (rest) 运算符是非常有用的。 如果函数无需返回任何值,你可以使用 void 作为返回类型。 在 PHP 和 AS3 中,你可以为自变量提供默认值。例如: 1: //php code 2: 3: function doThing($a, $b="default value") { 4: echo $a . $b; 5: } 6: 7: //AS code 8: function doThing(a:String, b:String="default value"):void { 9: trace(a + b); 10: } 当然,你可以在函数中定义函数(你将在下一个代码样本中看到一个范例)。 其次,在 AS3 中,任何函数将被表示为 Function 类的一个实例。这使得某些有趣的事成为可 能:  你可以创建一个文字函数并且将它赋值给一个变量,然后通过该变量调用该函数(这 在 PHP 中也能够实现)。  你可以返回一个函数作为另一个函数的执行结果。  当调用其它函数时,你可以将函数作为自变量传递。 1: var f:Function = function multiply(x:int, y:int):int { 2: return x*y;
  • 24. 3: } 4: 5: trace(f(3,5)); 6: 7: function giveMeAFunction():Function { 8: return function multiply(x:int, y:int):int { 9: return x*y; 10: }; 11: } 12: 13: var h:Function = giveMeAFunction(); 14: trace(h(3,4)); 在 PHP 和 AS3 中,你可以创建匿名函数(闭包)。在前面的代码样本中,你能够看到一个在 giveMeAFunction() 中创建一个匿名函数然后将其返回的范例。 也许 AS3 和 PHP 的函数之间的最大不同点是你定义它们的方式。在 PHP 中,你可以在文件中 定义任意数量的函数。而在 AS3 中,你在一个文件中只能定义一个函数,并且该函数的名称必 须与文件的名称相匹配。例如,如果你定义的函数的名称为 doSomeMath(),则你必须在一个名 称为 doSomeMath.as 的文件中创建该函数。在定义函数时,你可以使用类包声明(package declaration)(你将在下一章节学习与包相关的内容)。因此当你希望创建大量工具函数,如果 你不希望在大量文件中编写这些代码,则你可以创建一个单一类然后将它们定义为静态方法。 OOP:类和接口 现在是讨论 PHP 和 AS3 的面向对象编程(Object Oriented Programming )功能的时候了。在 PHP 中,你可以编写面向对象或程序化的代码;而 AS3 是面向对象的语言。 让我们从简单 PHP 类开始来看看语法的不同点(记住我使用 PHP 5.3 作为编程参考语言): 1: namespace orgcorlan { 2: 3: class SimpleClass { 4: 5: public $public = 'Public'; 6: protected $protected = 'Protected';
  • 25. 7: private $private = 'Private'; 8: 9: function SimpleClass() { 10: 11: } 12: // Redefine the parent method 13: function displayVar() 14: { 15: 16: } 17: } 18: } 19: 20: //use the class like this 21: require_once('flassFile.php'); 22: $obj = new orgcorlanSimpleClass(); 23: $obj->displayVar(); 在 AS3 中,相同的类编写如下: 1: package org.corlan { 2: 3: public class SimpleClass { 4: 5: public var _public:String = "Public"; 6: protected var _protected:String = "Protected"; 7: private var _private:String = "Private"; 8: 9: function SimpleClass() { 10:
  • 26. 11: } 12: 13: // Redefine the parent method 14: public function displayVar():void 15: { 16: 17: } 18: } 19: 20: } 21: 22: //you use the class like this: 23: import org.corlan.SimpleClass; 24: 25: var object:SimpleClass = new SimpleClass(); 26: object.displayVar(); 下面是它们的主要差异:  对存储类的文件进行命名 o 在 PHP 中,你可以在一个文件中定义一个类,而该文件可以以任意方式命名 o 在 AS3 中,文件的名称必须与类的名称相同 (如果类的名称为 SimpleClass, 则文件的名称必须为 SimpleClass.as)  命名空间 vs 类包 o 在 PHP 中,你可以使用命名空间以避免类之间的名称冲突 o 在 AS3 中,你可以使用类包;然而,例如,当你在 org.corlan 类包中声明一个 类时,这意味着该类将会包含于 Flex 源文件夹的 org/corlan 文件夹中。该包名 可以转变为一个文件夹结构。与类访问修饰符( class access-modifier)一起使 用的类包能够将该类隐藏至项目之外的类中(后面将会详细讨论)。  要求/包含 vs. 导入
  • 27. o 在 PHP 中,通常你可以使用 require_once 函数包含定义类的文件。从 PHP 5 开 始,你将能够定义一个__autoload() 函数,并且在该函数中包含 require_once 或 include_once,而不需在每个文件的顶部编写一个要求的文件的列表 。 o 在 AS3 中,你可以使用导入语句来包含期望的类。然而,如果你希望从类包 org.corlan 中包含所有类,你可以使用一个通配符编写该导入语句:import org.corlan.*。另一个不同之处是 AS3 编译器只编译那些在你的代码中实际使用 的类 (即只有在特定类的一个实例被实际创建的情形下) 。  调用方法/实例成员: o 在 PHP 中,你可以使用 “->” 运算符 o 在 AS3 中,你可以使用“.” (dot) 运算符 现在,让我们来讨论类/方法/成员修饰符。 我将从类修饰符开始讨论:  PHP 具有 final 和 abstract 类修饰符;而 public 是隐式类修饰符,在 PHP 中,所有类均 为 public。  AS3 具有 public、internal、final 和 dynamic 类修饰符。如果你没有指定任何访问修饰符 (public 或 internal),则该类默认为 internal,其含义为该类只能被来自相同类包的类 访问。public 和 final 与 PHP 具有相同的含义。abstract 在 AS3 中不存在,但你可以使 用接口克服这一限制。Dynamic 标示相应的类通过修改现有成员或添加新的成员能够在 运行时进行更改。 类特性(class property)修饰符:  PHP 具有 public、private、protected 和 static 修饰符。  AS3 具有 PHP 修饰符加上 internal 修饰符。Internal 可用于使得特性(property)只能在 相同类包的内部才是可用的。当没有指定修饰符时,可以使用 internal 修饰符。 类方法(class pmethod)修饰符:  PHP 具有 public、private、protected、static、final 和 abstract 修饰符。  AS3 具有 public、private、protected、static、final、internal 和 override 修饰符。abstract 在 AS3 中不存在;Internal 可以使得方法只能在相同类包的内部的代码中才是可用的。 在 AS3 中,你可以使用函数闭包实现的每一件事均可以使用类函数实现。
  • 28. PHP 的构造器可以标示为 private,你可以定义一个具有与类名称相同的构造器,或你可以使用 特定的方法__construct()和__destruct()。在 AS3 中,构造器总是具有 public 修饰符并且必须具有 与类相同的名称。如果没有提供任何修饰符,则 AS3 将为你在场景之后创建一个修饰符。 静态成员或静态方法是可以访问的:  在 PHP 中,使用 ClassName::propertyName。  在 AS3 中,使用 ClassName.propertyName。然而,在相同类的内部,你可以省略该类 名称。 1: package org.corlan { 2: 3: public class Foo { 4: 5: private static myVar:String; 6: 7: function Foo() { 8: Foo.myVar = "value 1"; 9: myVar = "value 2"; 10: } 11: 12: } 13: } 这里:  在 PHP 中,你可以使用特别的类变量$this 来指向在相同类中定义的类成员(变量/方 法): $this->myVar = 22。  在 AS3 中,你可以使用相同的 this:this.myVar = 22;然而,你可以忽略 this, 然后仅 使用 myVar = 22 即可。 在 AS3 中,只有一个类能够在类包的内部进行声明(一个 this 类可以给出该文件的名称)。然 而,在类包声明的外部,你可以声明任意数量的类: 1: package org.corlan { 2: 3: public class Foo { 4:
  • 29. 5: private static var instance:Foo; 6: 7: function Foo(object:Bar) { 8: 9: } 10: 11: static public getInstance():Foo { 12: if (Foo.instance == null) { 13: Foo.instance = new Foo(new Bar()); 14: } 15: return Foo.instance; 16: } 17: 18: } 19: 20: class Bar {} 这将产生一个有趣的效果:所有在类包外部的文件中定义的类将只能在相同文件内部声明的代 码中使用。对于所有其它代码,这些类不存在。记住 AS3 的限制,即你不能声明该构造器为 private。因此,通过使用与该范例相似的方法,你可以确保只存在一个 Foo 类的实例。如果某 外部代码调用该构造器时,系统将抛出一个运行时异常,因为外部代码不能使用 Bar 的实例并 且该类对于外部代码是不可见的。 继承 在 AS3 中进行类的扩展与在 PHP 中非常相似。你可以使用相同的 extends 关键词后面跟随你希 望扩展的类的名称。覆盖(Overriding)功能与 PHP 相同,有一点不同之处是你必须将 override 关键词添加至方法签名。AS3 不支持重载(Overloading)功能(你不能拥有两个或更多具有相 同名称的方法)。 在 PHP 中,你可以使用语句 parent::memberName 访问父成员;而在 AS3 中,你可以使用语句 super.memberName 访问父成员。当执行一个类的构造器时,首先应该调用父构造器。甚至当你 没有从你的代码中显式调用父构造器时也会发生父构造器调用。因此,当你在构造器方法中编 写代码时,你不能在你的代码之后放置父构造器的调用语句。这样,你可以为父类的正确初始
  • 30. 化提供了机会,因此子类将不会使用没有设置的成员。你可以使用语句 super()调用父构造器。 让我们来看看这些工作原理,先看 PHP 代码,然后再看 AS3 代码。 1: class SimpleClass { 2: 3: function SimpleClass() { 4: echo('SimpleClass() called'); 5: } 6: 7: function __construct() { 8: 9: } 10: 11: 12: function displayVar() 13: { 14: echo "SimpleClass classn"; 15: } 16: } 17: 18: class ExtendClass extends SimpleClass { 19: 20: function ExtendClass() { 21: $myVar = 1; 22: parent::SimpleClass(); 23: //or 24: parent::__construct(); 25: } 26: // Redefine the parent method 27: function displayVar()
  • 31. 28: { 29: echo "Extending classn"; 30: parent::displayVar(); 31: } 32: } 1: public class SimpleClass { 2: 3: function SimpleClass() { 4: trace("SimpleClass() called"); 5: } 6: 7: public function displayVar():void 8: { 9: trace("SimpleClass class"); 10: } 11: } 12: 13: public class ExtendClass extends SimpleClass { 14: 15: function ExtendClass() { 16: super(); //we have to call first the parent constructor, and only after we can execute our code 17: var myVar:int = 1; 18: } 19: 20: override public function displayVar():void { 21: trace("overrided displayVar()"); 22: super.displayVar(); 23: }
  • 32. 24: } 让我们看一下在 AS3 中类是如何初始化的。当一个类被例示时,首先其所有的特性 (property)将被初始化,其次在类级别定义的静态代码将被执行(这在 PHP 中是不能执行 的),最后构造器将被执行。下面是范例代码: 1: public class Foo { 2: 3: private var a:int = 0; 4: private static var os:String; 5: trace("initializer"); 6: 7: if (Capabilities.os == "LINUX") 8: os = "LINUX"; 9: else 10: os = "other"; 11: 12: public function Foo(a:int=1) { 13: trace("foo() executed"); 14: } 15: } 16: 17: var foo1:Foo = new Foo(); 18: var foo2:Foo = new Foo(); 19: //produces this output in console: 20: initializer 21: foo() executed 22: foo() executed 在 AS3 中,你可以使用函数的原型特性(property)创建函数闭包之外的对象(这与你在 JavaScript 中使用的函数来创建/扩展类的情况是相似的)。下面是一个简短范例代码: 1: //we create a function 2: function MyClass(value:String = "Mihai") {
  • 33. 3: //we create a property 4: this.name = value; 5: } 6: //we use the special variable prototype of the function 7: //to create another method 8: MyClass.prototype.setName = function (value:String):void { 9: //we have access to the property defined on MyClass object 10: trace(this.name); 11: this.name = value; 12: trace(this.name); 13: } 14: 15: //create an instance 16: var myObject = new MyClass(); 17: //accesing the method created earlier 18: myObject.setName("Joe"); 在后面的章节中,我将更多地讨论 AS3 的动态功能。 Getters/setters 在任何 OOP 语言中,你通常会使用 getters/setters 来控制你希望向外部暴露的类特性 (property)。PHP 也不例外。然而,在 AS3 中,可以使用关键词 set 和 get 对类特性 (property)提供特别支持。下面是范例代码: 1: public class Employee { 2: 3: private var _salary:int = 0; 4: private var _income:int = 0; 5: 6: function Employee() { 7: 8: }
  • 34. 9: 10: public function set salary(value:int):void { 11: if (value > 0) { 12: this._salary = value; 13: this._income = this._salary * 12; 14: } 15: } 16: 17: public function get salary():int { 18: return this._salary; 19: } 20: 21: public function get income():int { 22: return this.income; 23: } 24: } 25: 26: //using this class 27: var emp:Employee = new Employee(); 28: emp.salary = 1000; 29: trace(emp.income); 30: //this raise an error, because the income property is read-only 31: //for the outside code 32: emp.income = 120; 通常,尽管我使用 setter 和 getter 替代_salary 字段 ,但我可以调用这些方法,好像它们就是字 段或特性(property)而不是函数:以 object.salary = 20 替代 object.salary(20)。如果你选择不对 setter 进行定义,你可以获得只读特性(property)。这就是我使用_income 特性(property)所 实现的功能。 除了使得代码简洁一些之外,该功能还使得编写可以被其它应用程序使用的 API 或类更为简 单。假设在我的范例中,我选择创建_salary 字段作为一个 public 成员。如果后来我决定需要验
  • 35. 证能够设置的值,则我必须添加一个 setter。在 PHP 中,这可能需要使用如 myObject.setSalary() 的语句。此时,任何使用该类的代码将会被破坏;因此,代码必须使用 setter 进行更新。 在 AS3 中,你可以利用定义为 public var salary:int 的特性(property)来启动该类,并且当你决 定需要一个 setter 时,你可以对该变量重新命名,然后添加 public function set salary() 方法。使 用该类的任何代码将不受这一变更的影响,因为它仍然使用相同的语句 objectInstance.salary = 10 来访问该特性(property)。 在 AS3 中,当使用这种式样的 setter 和 getter 时,有一个惯例是在变量名称前添加一个下划 线。 接口 在 PHP 和 AS3 中,接口的工作方式几乎相同。一个显著的差异是在 PHP 中,你可以定义方法 以及常量,而在 AS3 中,你只能定义方法。然而,你可以定义 setter/getter: 1: public interface IEmployee { 2: 3: public function set salary(value:int); 4: public function get salary():int; 5: public function get income():int; 6: } 异常 正如在 PHP 中的那样,AS3 能够支持异常处理: 1: try { 2: 3: } catch(e:Error) { 4: 5: } finally { 6: 7: } 8: 9: //throwing an exception 10: throw new Error("Some error");
  • 36. 在 AS3 中,对于所有错误来说,Error 是顶级类。你可以创建自己的错误以扩展该类,或你可 以使用现有的子类。 对象类型的转换和测试 有时,你希望将一个对象强制转换为一种不同的类型,或希望检查对象类型。在 PHP 中,你可 以使用 instanceof 检查对象的类型,而在 AS3 中,你可以使用 is 检查对象的类型。为了进行类 型强制转换,在 AS3 中,你可以使用两种不同的语句。 1: class A {}; 2: 3: class B extends A {}; 4: 5: var b:A = new B(); 6: //casting 7: var c:B = b as B; 8: //or 9: var d:B = B(b); 10: 11: //checking the type of an variable 12: if (b is A) 13: trace(true); 14: if (b is B) 15: trace(true); 变量作用域 前面我们已经了解了变量、函数和类是如何在 Flex 和 AS 3 中工作的,现在是讨论变量作用域 的时候了。在 PHP 中,通常你具有两个作用域:全局(global)(在文件级别定义的变量)和 本地(local )(在函数内部定义的变量)。 在 Flex 中,共有 5 个作用域:函数体(function body)、实例方法体(instance method body)、静态方法体( static method body)、类体(class body)和全局作用域(global scope)。向这些作用域添加访问修饰符(public/private/protected/internal)使得事情比在 PHP 中 变得更为复杂。
  • 37. 作用域可以嵌套。在本例中包含的作用域的变量/函数/成员均可以被嵌套的变量/函数/成员使 用。例如,当你在另一个函数体的内部声明一个匿名函数时,在 AS3 中,所有在外部函数定义 的变量可以在嵌套函数的内部使用。在 PHP 中,你必须传递你希望使用的变量,或添加 use 语 句: 1: //php code 2: function a() { 3: $a = 1; 4: $b = 2; 5: 6: function b() use ($a, $b) { 7: 8: } 9: } 10: 11: //AS3 code 12: function a():void { 13: var a:int = 1; 14: var b:int = 2; 15: 16: function b():void { 17: //variables a and b are available here 18: } 19: } 当你在一个未命名类包的内部声明一个函数时,其将被放置在全局作用域之中并且其对所有代 码均为可用的。然而,尽管在一个类包之外声明的任何函数仍然位于全局作用域,但其只能对 来自相同文件对代码是可见的。 数组 在 AS3 中,数组与 PHP 的情况非常相似,仅有一处差异:在 AS3 中,一个数组仅具有数字下 标。如果你希望创建一个关联数组,你可以使用 Object 类。如果你希望创建一个 key 是对象 (而非字符串)的哈希图(hash map)时,你可以使用 Dictionary 类。你可以使用 Array 类创建
  • 38. 数组,也可以创建多维数组。对于 Object 和 Array ,你均可以使用文字定义。让我们来看看若 干范例: 1: var myArray1:Array = new Array(1, 2, "some string"); 2: //creates an array with three elements: 0->1, 1->2, 3->some string 3: 4: //literal definition for an array 5: var myArray2:Array = [1, 2, 3]; 6: //ading two more elements 7: myArray2.push(4,5); 8: 9: //a hash map, similar to associative arrays in PHP 10: var myMap:Object = new Object(); 11: myMap.name = "Flex"; 12: //literal definition of a map 13: var myMap2:Object = {name:"Flex"}; 14: 15: //using Dictionary class 16: var dic:Dictionary = new Dictionary(); 17: var anObject:Object = new Object(); //creating the key 18: dic[anObject] = "some value"; //adding a value to Dictionary 你具有添加元素或删除元素的所有期望的方法,包括 push、shift、pop、unshift 和 splice。 Concat 可以用于将数组添加至另一个数组。在前面的范例中,你可以看到我是如何使用 push 来添加另外两个元素至一个数组。 数组具有不固定的长度。其长度随着你添加更多元素而增加。在 PHP 中,你可以使用“[]” 在数 组的结束部分添加一个新的元素。AS3 具有相似的方法,该方法使用数组的 length 特性 (property )(你也能够使用 length 特性(property )来声明数组的长度)。 1: var array:Array = new Array(); 2: array[array.length] = 1;//array has the values: 1 3: array[array.length] = 23;//array has the values: 1, 23
  • 39. 你可以使用 delete 将数组的一个特定元素设置为 undefined:delete array[index]。这一操作将不 会缩短数组的长度。你可以使用 for() 语句并且利用其 length 特性(property )对数组进行循环 操作。如果你希望对一个 Object 进行循环操作(这可以用于创建与 PHP 关联数组相似的数 组),你可以使用 for – each (其工作方式与 PHP 中相同的构造器相似) 或 for – in 语句(在 动态 (Dynamic)章节将会更多地对其进行讨论 )。 命名空间 如果你希望寻找与 PHP 命名空间对等的 AS3 概念,你应该阅读类(Classes)章节关于类包的 内容,因为 AS3 类包与 PHP 命名空间是相似的。 在 ActionScript 中,命名空间具有不同的含义。让我们来看看命名空间可以用来干什么,然 后,我将给出若干范例: 1. 防止命名冲突(你可以在相同的类中创建具有相同名称的多个方法,每个方法存储于 不同的命名空间) 2. 向自定义 visibility 设置标示跨框架/程序的变量和方法(例如,Flex 使用一个名称为 mx_internal 的命名空间;使用该命名空间而不使用 private 或 protected 使得使用这些来 自 Flex 框架的跨类包和类的方法成为可能。同时,开发人员将被警告这些方法或成员 不一定能够被外部使用,因为它们可能会改变) 3. 实现基于许可的类的访问控制功能 4. 创建能够基于特定选择的命名空间来改变其行为的类 在详细讨论命名空间之前,我们应该注意到命名空间可以被 Flash Player 内部使用以实现访问修 饰符:public、protected、internal 和 private。 你可以使用语句 namespace identifier = URI 定义一个命名空间。当你声明变量/方法以及希望限 定一个成员或方法以便使用它时,你应该使用标识符。URI 通常是一个 URL ,该 URL 对于你 的应用程序来说必须是唯一的。它并不是必须存在的,并且在大多数情形下,你应该使用你的 域名。例如,我可以定义一个如下形式的命名空间:namespace online = “http://corlan.org/apps/online”。 你可以在能够定义变量的任何位置定义命名空间:在类包定义的顶层(它在整个程序中均可 用),或在类级别(它只能在定义它的类中可用)。在函数级别,你只能使用在其它位置定义 的命名空间(你可能需要这样做以便限定一个在其它位置使用相同命名空间定义的变量;你需 要知道相应的 URI 以便进行限定)。 你可以通过在相应声明之前放置命名空间标识符,在一个给定的命名空间中声明一个方法或变 量。例如:mynamespace var a:int = 1。当你在一个命名空间中定义一个变量或方法时,系统不 允许你使用其它访问修饰符(例如 private )。
  • 40. 为了调用在一个命名空间定义的变量或方法,你可以使用命名修饰符运算符“::”。假设你在一 个名称为 online 的命名空间中定义了一个名称为 myMethod() 的方法,你就可以使用语句 objectInstance.online::myMethod() 访问该方法。对变量来说,情形也是相同。有时,你可能需要 使用那些利用命名空间名称限制的变量或方法。你可以在相应的作用域打开该命名空间并且摆 脱该命名修饰符运算符的限制。你可以使用 use namespace namespaceidentifier 指令实现这一目 的。例如: 1: public function doSomething() { 2: use namespace online; 3: //call the method defined in that namespace: 4: myMethod(); 5: } 你可以传送命名空间,例如,你可以从一个方法中返回一个命名空间,以便允许该调用代码使 用它来限定一个方法或成员。 现在,让我们来创建两个命名空间,它们可以用于在运行时改变类的行为。首先,我将定义这 两个命名空间(我将为每个命名空间提供一个文件): 1: // ActionScript file online.as 2: package org.corlan { 3: public namespace online = "http://corlan.org/apps/online"; 4: } 1: // ActionScript file offline.as 2: package org.corlan { 3: public namespace offline = "http://corlan.org/apps/offline"; 4: } 接下来,我将使用这两个命名空间创建一个能够存储一个对象的类。根据其链接状态,该类可 以在本地存储该对象(例如,使用本地存储设备),或以远端方式在服务器上存储该对象(使 用 REST 服务)。当某些代码需要使用该类时,有趣的部分将会出现。该调用的代码完全不关 心该方法,它只希望将该对象存储起来。 通过使用这两个命名空间,我将创建一个类,该类具有两个名称均为 save()的方法,每个方法 定义于其中一个命名空间。下一步,我将创建一个私有变量,该变量存储了当前的命名空间, 根据因特网连接的状态可以使用该命名空间。调用程序可以使用 getter 访问当前命名空间,并 且使用它来调用 save() 方法。再一次强调一下,调用程序不知道所有的这些 internal,而且不知 道这些命名空间,它也不关心这些命名空间。让我们看一下 PersistObject 代码: 1: package org.corlan {
  • 41. 2: import flash.events.Event; 3: 4: public class PersistObject { 5: 6: private var _mode:Namespace = offline; 7: 8: public function PersistObject() { 9: 10: } 11: 12: online function save(object:Object):void { 13: //save the object back to server 14: trace("online"); 15: } 16: 17: offline function save(object:Object):void { 18: //save the object locally 19: trace("offline"); 20: } 21: 22: private function connectivityChanged(e:Event):void { 23: //here the mode can be changed from offline to online 24: //and vice-versa 25: } 26: 27: public function get mode():Namespace { 28: return this._mode; 29: } 30: }
  • 42. 31: } 下面的代码片段使用了该类。该代码段非常简单,并且行内的注释给出了说明。 1: //creating an object that we want to be stored 2: var object:Object = {book:"Ulysses", author:"James Joyce"}; 3: //create an instance of PersitObject 4: var persistenceObject:PersistObject = new PersistObject(); 5: //get the current namespace 6: var currentMode:Namespace = persistenceObject.mode; 7: //use the namespace we retrieved to qualify the save method() 8: persistenceObject.currentMode::save(object); 命名空间可访问性 你可以使用与变量或方法相同的访问修饰符:public, internal, protected 和 private (对于在类包级 别定义的命名空间,你可以只使用 public 和 internal)。将这一点与命名空间定义的位置结合起 来,你将对程序中命名空间的可见性具有很强的控制能力。 与 XML 的配合 在 PHP 中,通过本机函数或附加扩展对 XML 提供了大量支持功能。在 AS3 中,本机有两个类 可以表示 XML:XML 和 XMLList。AS3 能够基于 W3C DOM (你可以使用像 children()、 appendChild()、parent()、 insertChildBefore() 等方法) 实现 XML 类。当你利用 XML 进行编程 时,你应该了解如何使用 E4X。E4X (ECMAScript-for-XML) 是 ECMA-262 语言的一种扩展, 该扩展是通过 AS3 实现的。你可以使用 XML 来表示一个 XML 文档。即使在只有一个子类的 情形下,任何来自该文档的节点都将包含于一个 XMLList。 你可以使用下列任何方法创建一个 XML 对象: 1. 使用文字形式编写 XML。 2. 创建一个 XML 实例,然后从一个外部文件导入该 XML 实例。 3. 创建一个 XML 实例,然后使用点记法(dot notation)以便添加/改变相应的结构: 1: var author:XML = <author/>; 2: author.@id = 1; //setting an attribute called id and its value 3: //adding two child nodes to author: 4: author.name = "Mihai Corlan";
  • 43. 5: author.article = "Flex for PHP developers"; 6: 7: //this code is equivalent with: 8: var author:XML = <author id="1"> 9: <name>Mihai Corlan</name> 10: <article>Flex for PHP developers</article> 11: </author>; 通过使用 E4X,你可以根据基于节点名称或属性值的创建条件很容易地找到节点。你可以使用 递减运算符 “..” 查询具有给定名称的所有节点(例如,为了查询所有程序节点,你可以使用语 句:programs..program)。你可以使用“@” 运算符 (例如, programs..program.(@id==2))创建 基于属性的条件。最后,通过使用点符号,你可以在节点之间浏览(应该记住即使在只有一个 子类的情形下,任何子类均被看作一个 XMLList)。下面你将看到使用 E4X 与 XML 配合的范 例: 1: var programs:XML = <root> 2: <program id="1"> 3: <name>Flex</name> 4: </program> 5: <program id="2"> 6: <name>ActionScript 3</name> 7: </program> 8: <program id="3"> 9: <name>AJAX</name> 10: </program> 11: </root>; 12: 13: //retrieving the second program node and printing its name 14: trace(programs.program[2].name[0]); 15: //retrieving all the program nodes: 16: var list:XMLList = programs..program; 17: //retrieving all the program nodes that have an id attribute equal to 2
  • 44. 18: var list:XMLList = pograms..program.(@id==2); 动态 ActionScript 还记得 AS3 的定义吗?在该定义中,我给出了 AS3 是一种动态脚本语言的陈述。让我们更进一 步地讨论该功能。动态表示通过添加或删除方法或成员可以在运行时修改一个对象。系统能够 将新的方法添加至类的本身(并且任何由该类创建的对象将具有这些方法)。你甚至可以从头 创建新类(使用 protoype 特性(property))。AS3 具有内置的动态对象,例如 Object,而 Flex 具有另一个动态对象例子:ObjectProx。 如果你想知道为什么该功能首先出现,其答案是非常简单的:ActionScript 的早期版本不具有 AS3 今天提供的所有功能和 OOP。我必须说明,以我的经验来看,没有多少开发人员使用 AS3 的动态功能。这里有下面几个原因。首先,动态成员的访问速度要慢于固定成员。其次,你的 代码更易于出现软件缺陷(例如,没有编译时间错误检查)。 你可以不局限于使用内置类;你能够在类定义中使用 dynamic 修饰符创建动态对象: 1: dynamic public MyDynamicObject { 2: 3: } 现在,通过使用你刚才定义的类,你可以在运行时添加成员(记住所有动态实例变量均为 untyped 和 public): 1: var a:MyDynamicObject = new MyDynamicObject(); 2: a.author = "Mihai Corlan"; 你可以使用 for-each-in 循环语句将一个动态类的所有成员遍历一次。下面是如何从前面的范例 中显示成员的代码: 1: for each (var element:* in a) { 2: trace(element); //displays Mihai Corlan 3: } 如果你希望获得成员名称而不是其值,你可以使用 for-in 循环语句: 1: for (var memberName:* in a) { 2: trace(memberName); //outputs author 3: trace(a[memberName]); //outputs Mihai Corlan 4: }
  • 45. Flex 是异步的 到目前为止,我们已经讨论了许多 Flex 功能,并且其中大部分功能与其 PHP 的对等部分非常 相似。但是,Flex 的异步特性与 PHP 相比具有相当的差异。停止与之对抗并且顺其自然,了解 这一点非常重要。 “Flex 是异步的”这句话的含义是什么?假设你创建一个 Flex 应用程序,并且在该应用程序载入 浏览器之后,用户可以选择从另一个站点下载图片。你也许使用一个 URLLoader 类来实现这一 任务。当你执行 load() 方法时,在代码的下一行,你将不会拥有相应数据。在 load() 调用等待 相应数据已经载入之后,脚本不会暂停。取而代之的是脚本的执行将被恢复。作为一个程序 员,你可以使用内置的 AS3 事件系统处理这一异步特性。如果你熟悉 AJAX 编程,这与你在执 行一个 AJAX 调用时所做的事情相似:你提供一个回调函数,并且当数据到达时,该回调函数 将被调用并且你可以访问相应的下载数据。 回到 ULRLoader 范例,你可以为 result 事件添加一个事件侦听器。这是一个函数,当数据载入 之后,它将被调用。 1: function loadPic():void { 2: var loader:URLLoader = new URLLoader(); 3: loader.dataFormat = URLLoaderDataFormat.BINARY; 4: //adding the event handlers or listeners 5: loader.addEventListener(EventComplete, picLoaded); 6: loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, picError); 7: //starting the loading 8: loader.load(new URLRequest("http://some_url")); 9: } 10: 11: //event handler for 12: function picLoaded(event:Event):void { 13: //get the data from the loader object 14: //use the target property to get the loader object 15: (event.target as URLLoader).data; 16: } 17: 18: //event handler for the error event
  • 46. 19: function picError(event:IOErrorEvent):void { 20: //displays the error id in a pop-up windonw 21: Alert.show(event.errorID); 22: } 我从上面代码得出的功能概述是:别调用我们,我们将调用你们! 正如我在前面所述的那样,AS3 具有内置的事件系统。所有事件的顶级类是 Event。所有异步 工作的对象均具有 addEventListner() 方法,并且前面两个自变量为事件类型,以及在事件发生 时被调用的函数的名称。你可以认为只有处理检索的远端数据的对象才遵从该事件模型。实际 的情况并非如此;所有可见的组件或对象也具有各种事件。例如,每个 Flex 应用程序具有一个 creationComplete 事件。当所有应用程序要求的组件被处理并且在屏幕上绘制之后,该事件将被 触发。 尽管你可能感觉这样的代码不如 PHP 的代码简单易懂,但对于在 Flex(以及 Flash Player)中 随处可见的异步调用来说,这里具有一个恰当的理由:Flex 是一种客户端侧技术。例如,如果 所有调用均为同步调用,则应用程序的用户界面将会停止对涉及下载数据的调用的响应。而用 户非常厌恶不能对用户界面及时响应。 你可以删除一些事件,甚至能够改变其默认行为。如果你愿意,我将让你自己研究这些详细内 容。从现在开始,你应该对什么是事件和事件侦听器具有相当清晰的理解。 数据绑定、元数据标签和反射 数据绑定是另一个能够使得开发人员的生活更为轻松的 Flex 功能,并且同时能够减少代码的行 数。数据绑定是一种能够将数据模型与视图进行绑定的很好方法,并且能够自动更新视图以反 映任何数据模型的变化。 因为 Flex 可以用于创建应用程序的用户界面,因此 Flex 组件通常是以显示大量数据的方式结束 的。当数据被修改时,甚至在实时修改的情形下,通常,人们希望显示最新的而不是老旧的数 据。通过使用数据绑定功能,你能够轻松地实现这一目标。数据绑定可以将一个对象的特性 (property)(称为源)与另一个对象的特性(property)(称为目的地)进行链接,因此,每 当源改变时,相应的目的地将自动更新。 Flex 4 支持双向绑定功能(实际上 Flex 3 也支持该功能,但你需要在第二步对其进行声明), 这意味着绑定功能在另一个方向也能起作用:即当目的地被更新时,新的值将被复制到相应的 源。当你具有一个数据模型和一个表单时,这是非常有用的。你可以将数据模型与表单进行绑 定,然后当用户改变表单中的值时,双向数据绑定功能将会利用表单的值来更新数据模型。现 在,让我们来看看一些代码: 1: <?xml version="1.0" encoding="utf-8"?>
  • 47. 2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal"> 3: <mx:Script> 4: <![CDATA[ 5: 6: [Bindable] 7: private var labelValue:String = "Hello World!"; 8: 9: private function add():void { 10: labelValue += "!"; 11: } 12: ]]> 13: </mx:Script> 14: <mx:Label id="myLabel" text="{labelValue}"/> 15: <mx:Button label="Add a !" click="add()"/> 16: </mx:Application> labelValue 变量的 Bindable 元数据可以将其标示为数据绑定的源。下一步,我对 Label 的文本属 性使用了“{}” 符号以便将该特性(property )标示为该绑定的目的地。在设置绑定功能之后, 每当变量 labelValue 被改变时,标签将更新其视图以反映相应的改变。我可以针对许多标签或 文本输入使用相同的变量,而且他们都能够被更新以反映新的值。 这里也存在一个具有相同功能的 MXML 语句:<mx:Binding source=”labelValue” destination=”myLabel.text”/>。如果你希望将该数据与一个可编辑的控件(例如,一种文本输 入)进行绑定,然后复制该值到该源,那么在 Flex 4 中,你可以使用“@” 运算符现实双向绑定 功能: 1: <s:TextInput id="txt" text="@{labelValue}"/> 之后,如果你希望使用 Binding 标签,则你可以将属性 twoWay 设置为 true(再一次声明,这只 能适用于 Flex 4): 1: <mx:Binding source="labelValue" destination="myTextBox.text" twoWay="true"/> 为了实现数据绑定功能,Flex 在编译时间添加了胶水代码(glue code )(记住数据绑定不是 Flash Player 或 AS3 的功能),这样做的美妙之处是你不需要自己编写该代码。 尽管数据绑定功能为数据模型与视图的绑定提供了一种简单易懂的方法,但是,如果你具有大 量的变量绑定,并且它们每秒更新数百次,则会对性能产生影响。对于这样的变量,没有必要
  • 48. 对用户界面进行如此频繁的更新,因为对浏览器自己执行的每秒帧数(大约每秒 50 帧)有相应 的限制。因此,试图每秒实时显示数百次变更是毫无意义的。 另一个需要记住的事情是并不是所有的对象均为可绑定的。例如,Object 和 Array 都不是可绑 定的,因此,你应该使用 ObjectProxie 和 ArrayCollection。当你创建类以便为数据建立模型 时,如果你希望该类的所有成员均为可绑定的,则你应该将 Bindable 元数据放置在类级别之 上,而不是为每个特性(property)添加 Bindable 元数据: 1: package org.corlan { 2: 3: [Bindable] 4: public class VOAuthor { 5: 6: public var id_aut:int; 7: public var fname_aut:String; 8: public var lname_aut:String; 9: } 10: } 现在,让我们讨论一下元数据标签(有时称为注解)。你已经看到了以 Bindable 元数据标签的 形式出现的元数据标签。如需获得你能够在 Flex 中使用的元数据标签的完整列表,请点击这 里。在一些情形下,MXML 编译器可以使用元数据标签以便产生胶水代码(如在 Bindable 的 情形下),而在另一些情形下,你可以使用元数据标签来向 Flash Builder IDE 发送示意,或在 MXML 标签中创建特性(property)。这是 Event 元数据的情形。例如,假设我编写一个类,它 能够在载入一个电影时抛出一个事件。我可以使用 Event 元数据声明该事件的类型和名称。之 后,我可以使用 MovieLoader MXML 标签的 movieLoadedEvent 特性(property)来为该事件注 册事件侦听器。让我们看看该类的代码以及如何在 MXML 中使用该类。 1: //class definition 2: package org.corlan { 3: import flash.events.EventDispatcher; 4: import flash.events.IEventDispatcher; 5: 6: [Event(name="movieLoadedEvent", type="flash.events.Event")] 7: 8: public class MovieLoader extends EventDispatcher {
  • 49. 9: 10: public function MovieLoader(target:IEventDispatcher=null) { 11: super(target); 12: } 13: 14: } 15: } 1: <?xml version="1.0" encoding="utf-8"?> 2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 3: xmlns:local="org.corlan.*" layout="horizontal"> 4: <mx:Script> 5: <![CDATA[ 6: private function movieLoadedListener(event:Event):void { 7: //do something with it 8: } 9: ]]> 10: </mx:Script> 11: 12: <local:MovieLoader id="loader" movieLoadedEvent="movieLoadedListener(event)"/> 13: </mx:Application> 这里还有其它与元数据相关的有趣事情。如果你在编译器上设置一个标志(keep-as3-metadata 后面跟随一个标签的名称),则你可以添加你的自定义元数据标签,并且编译器将会把这些标 签放入字节代码(bytecode)中。之后,你可以在运行时使用这些标签。例如,点击这里,你 可以阅读到如何使用自定义元数据标签为在一个 AIR 应用程序中存储一个给定数据模型提供一 种方法(稍后将更多地讨论 Adobe AIR )。 现在,我们将讨论本节的最后一个话题:反射。为了能够使用自定义元数据,你必须依靠 AS3 反射 API。 在 PHP 中,存在一个完整的面向对象的反射 API 系列:其中包括 Reflection、 ReflectionFunction、ReflectionParameter、ReflectionMethod 等等。下面是一个在简单 PHP 类之 上使用 Reflection 类的范例: 1: class SimpleClass {
  • 50. 2: 3: public $public = 'Public'; 4: protected $protected = 'Protected'; 5: private $private = 'Private'; 6: 7: private function SimpleClass() { 8: echo('SimpleClass() called'); 9: } 10: 11: private function __construct() { 12: 13: } 14: 15: function displayVar() { 16: echo "SimpleClass classn"; 17: } 18: } 19: 20: 21: Reflection::export(new ReflectionClass('SimpleClass')); //this outputs: 22: 23: Class [ <user> class SimpleClass ] { 24: @@ /Applications/MAMP/htdocs/_learning/classes.php 7-26 25: 26: - Constants [0] { 27: } 28: 29: - Static properties [0] { 30: }
  • 51. 31: 32: - Static methods [0] { 33: } 34: 35: - Properties [3] { 36: Property [ <default> public $public ] 37: Property [ <default> protected $protected ] 38: Property [ <default> private $private ] 39: } 40: 41: - Methods [3] { 42: Method [ <user> private method SimpleClass ] { 43: @@ /Applications/MAMP/htdocs/_learning/classes.php 13 - 15 44: } 45: 46: Method [ <user, ctor> private method __construct ] { 47: @@ /Applications/MAMP/htdocs/_learning/classes.php 17 - 19 48: } 49: 50: Method [ <user> public method displayVar ] { 51: @@ /Applications/MAMP/htdocs/_learning/classes.php 22 - 25 52: } 53: } 54: } 55: 在 AS3 中,可以用于反射的 flash.utils 类包具有 3 个函数:describeType()、 getDefintionByNameI() 和 getQualifiedSuperClassName()。下面是一个 describeType() 输出的范例 (该输出是一个 XML 对象): 1: public class SimpleClass { 2:
  • 52. 3: public var _public:String = "Public"; 4: protected var _protected:String = "Protected"; 5: private var _private:String = "Private"; 6: 7: function SimpleClass() { 8: trace("SimpleClass() called"); 9: } 10: 11: public function displayVar():void 12: { 13: trace("SimpleClass class"); 14: } 15: } 16: 17: function reflect():void { 18: var s:SimpleClass = new SimpleClass(); 19: var description:XML = describeType(s); 20: trace(description); 21: } 22: 23: //the output: 24: <type name="org.corlan::SimpleClass" base="Object" isDynamic="false" isFinal="false" isStatic="false"> 25: <extendsClass type="Object"/> 26: <method name="displayVar" declaredBy="org.corlan::SimpleClass" returnType="void"/> 27: <variable name="_public" type="String"/> 28: </type> 我的数据在哪里?将它显示出来!
  • 53. 作为一个 PHP 开发人员,你可以使用非常直接的方法读取数据、解析数据并且将这些数据在屏 幕上显示出来。连接 MySQL 数据库是每一个 PHP 开发人员需要学会的第一件事情。实际上, 我非常怀疑你能够一直阅读通篇文章至此而没有先偷看这一章节。 Flex 怎么样呢?我不得不令你失望,因为你没有通向存储于数据库中的数据直接入口。不过, 我猜想这其中肯定有些好事,因为你可以继续编写 PHP 文件来读/写数据库中的数据,甚至在 编写 Flex 应用程序时也是如此 。为什么没有从数据库中读取数据的直接方法?因为有句老 话说得好:“你应该绝不相信客户端!” 假设客户端是一个知道如何连接 MySQL 服务器的 Flex 组件。你如何存储其信任状 (credential)才能使得其不容易被盗并且数据库的安全不受损害?为每个用户设置一个不同的 用户密码然后向他们发送该信息?这就是为什么使用客户端技术直接连接数据库服务器,而不 通过在中间使用应用程序服务器不是一个好主意的原因之一。 通常,在 Flex 应用程序中,你可以利用服务器侧的脚本来管理数据库。Flex 可以为你提供一种 调用服务器页面并且在 Flex 中返回相应的响应的方法。共有 3 种不同的连接服务器数据源的方 式:REST 式样服务、 web 服务和 Remoting (或 RPC)。 你可以利用 HTTPService 类来使用 REST 式样服务。当你需要发起一个请求时,你可以发送 POST 变量,并且其响应可以是 XML、JSON (这里有一个用于解析 JSON 的第三方库)或自 定义格式。 如果在服务器(SOAP/WSDL)上具有 Web 服务,你可以使用 WebService 类。 但最有趣的方法是 remoting (使用 RemoteObject 类)。为什么我认为它是最酷的方法,这里有 3 个原因:首先,通过使用 remoting,你可以通过调用任一 public 方法在你的服务器上充分利 用你拥有的 PHP 类。通常,在 Flex 侧,你可以使用 RemoteObject 的实例,好像其就是远端 PHP 类。其次,你可以将数据模型从 PHP 侧映射到 ActionScript 数据模型,并且使得其自动完 成转换。这是极为重要的,因为当你使用具有类型的对象时,你能够获得编译时间错误检查和 代码完成功能的益处。这意味着代码更易于阅读并且不易出现软件缺陷。第三,该方法的消息 格式-AMF3 (Action Message Format) 是二进制格式,该格式与 SOAP/XML/JSON 相比运行速度 更快而且占用空间更小,特别地,对于具有大量数据的应用程序更是如此。该格式本身是开放 的,而且所有的开发人员均可以阅读相关的白皮书并且能够实现使用该格式的程序。
  • 54. AMF3 之所以运行速度较快,是因为它能够对数据进行编码。因为,如果在一个数据集合中具 有重复的相同字符串,则该字符串只需进行一次编码,而所有其它字符串的出现均为引用。如 果一个数字少于 4 个比特,则只使用要求的最少数量的字节。 Adobe 的 James Ward 已经创建一种很好的测试方法,该测试方法能够说明 remoting 和其它方法 之间的不同之处。 Flex 在本机能够支持 Remoting,但在服务器侧情况却是不同的。PHP 不能在本机支持 remoting 和 AMF3。这是为什么你需要一个服务器侧库来支持 PHP Web 服务器的 remoting 功能。共有 4 个可用的库,并且全部能够免费使用。我已经编写了关于如何使用这些库的指南:Zend AMF, PHPAMF, WebORB for PHP, SabreAMF。点击这里,你可以阅读一篇对它们进行比较的文章。 因为本机数据类型能够自动转换(PHP 类型至 AS3 类型的转换以及相反方向的转换),因此你 必须关注来自一种语言的本机类型是如何转换为其它类型的。这里 是一个 AMFPHP 库中的数 据类型一致性的范例。 Flex 和 PHP 项目的用户授权 在 Flex 和 PHP 项目中用户授权是如何进行的呢?答案非常简单,与 PHP Web 站点相同,你可 以使用会话和某种方法来验证用户密码即可。 通常,当在 Flex 中执行一个调用时,会话 ID 将会被自动挂起。因此,如果之前已经对用户进 行授权,则将使用相同的会话。 点击这里,你将会获得关于该话题的更多信息。 建立 Flex 和 PHP 项目 令人欣慰的是,PHP 和 Flex 均为成熟技术,因此当需要使用工具时,你可以具有大量的选择。 我将在本章节中讨论其中一些工具。