Upcoming webinars on the Flash Platform
The summer is almost over (at least in the northern hemisphere :D) which means you are in one of these two situations: either you just came back from vacation or you’re about to take one. Either way, I think you’ll find (some of) the webinars we are doing this month quite interesting. As usually, they are free; you just have to sign up and show up. A word of warning: because all four of these webinars are delivered by EMEA platform evangelist, we decided to schedule them in such a way that works for Europeans.
Here is the list:
- Building Multi-Screen / Interconnected apps for Android and desktops (Mihai Corlan) – Friday, Augst 20
- Summer Cocktail: Doctrine 2, Zend Framework, Flex, and Flash Builder (Mihai Corlan)- Tuesday, August 24
- Advanced P2P programming in Flash (Tom Krcha) – Friday, August 27
- Presentation Model pattern with Flex and Swiz Framework (Piotr Walczyszyn) – Tuesday, August 31, 2010
Enjoy!
Working with Doctrine 2, Flex, Zend AMF, and Flash Builder
I finally got some time to play with Doctrine 2 and Flex. Back in May I wrote an article about working with Doctrine 1.x and Flex (you can read the article here) and my feelings were mixed. I chatted with Jonathan Wage of Doctrine about some of the shortcomings I found in Doctrine 1.x and his response was to check Doctrine 2 (still in development at the time of writing this article). Doctrine 2 is a big step forward.
In this article I describe how I rewrote the original application I created for my first article, this time using Doctrine 2, Flex 4, Zend Framework, and the Flash Builder data-centric development wizards. I’ll highlight the relevant differences between Doctrine 1 and Doctrine 2 along the way. Thus, you should find this article valuable in any one of these two cases:
- You are already working with Doctrine 1 and you’ve wondered what it would take to move to version 2
- You want to learn how to use Doctrine 2 with Flex; you know PHP and you know enough Flex not to be scared away if you see some snippets of code
Before going into the details let me say this: if you aren’t already using an ORM framework for PHP then you should. For most projects it can help you by freeing you of the tedious tasks of writing CRUD code and SQL queries. It allows you to focus on the business logic of your application. And all these advantages are multiplied when working on Rich Internet Applications because on this kind of project much of the work is done on the client and not on the server.
There are some aspects of using this ORM with RIA that could be better, but hey we don’t live in a perfect world. Most of these things, I think, are related to the fact that every time you use a server side ORM with a rich client, you leave behind the main story used for creating that framework – you use the ORM in order to feed a rich client with data and enable the client to persist the changes. Thus you need additional boiler plate code to make the whole thing work.
If you don’t know much about ORMs in general, you may want to read my first article first and before continuing.
50 resources to get up to speed with the Flash Platform
For the past six months we’ve been rolling out a lot of goodies, some of them in the form of final releases, others as betas. It’s no wonder you have to spend some time in order to get up to speed with the latest features of AIR 2, Flash Player 10.1 for Android, AIR 2.5, Flex 4, or Flash Builder 4. Thus, I thought it’d be a great idea to put together a list of resources to help you learn about these goodies.
So here I go, in no particular order.
Peer 2 Peer
Flash Player 10.1 and Adobe AIR 2 brings new capabilities to the table when it comes to Peer 2 Peer. The best resource to learn about this is my fellow evangelist Tom Krcha (some say his dreams are multicasted, but only a few are lucky enough to receive them :D):
- Multicast Explained in Flash Player 10.1
- File sharing over P2P in Flash Player 10.1 with Object Replication
- P2P GroupSpecifier Class Explained
- Direct Routing Explained in Flash Player 10.1
- Simple chat with P2P NetGroup in Flash Player 10.1
Flex and server side technologies
- Christophe Coenraets wrote about tuning client-side performance using Flex 4 and LiveCycle Data Services
- Ryan Stewart’s article on creating a basic CRUD application using Flex and PHP with Zend AMF
- If you prefer to use the Data Centric Development features of Flash Builder when working with Flex and PHP check out this article
- Debugging Flex and PHP projects with Flash Builder 4 and Eclipse PDT/XDebug
- Using Flash Builder 4 to build a Flex application that consumes a .NET-based web service written in C#
AIR 2
- Understanding the security changes in Flash Player 10.1 and AIR 2
- Creating a Web Server using the new Server Socket API in AIR 2
- Exploring the “open with default application” API
- Exploring the Native Processes API: here, here, here, and here
- Retrieving a list of network interfaces in Adobe AIR 2
- Creating a socket server in Adobe AIR 2
- Using drag-and-drop support of remote files in Adobe AIR 2
- Writing multiscreen AIR apps
- AIR 2 and Enterprise
- Developing AIR offline applications using the ColdFusion 9.0.1 ActionScript ORM Library
- Ten tips for building better Adobe AIR applications
AIR/Flash Player 10.1 and Android
- Mark Doherty’s P2P Video Calls on Android tutorial
- AIR 2.5 StageWebView demo
- Geolocation in AIR
- Video chat for Android using LiveCycle Collaboration Service and AIR
- Android apps that connects to desktop apps using Peer 2 Peer: here and here
- Setting up the tools for creating AIR for Android apps and accessing the camera from AIR
- Android Trader Desktop with Flex and AIR for Android
- “VoiceNotes for Android”: Sample App using Flex, AIR, and the Microphone API
- Serge Jespers’s native installers packager
Flex 4
- What’s new in Flex 4
- Differences between Flex 3 and Flex 4
- Skinning in Flex 4
- Introduction to Flex 4 (Spark) layouts
- New Animation Engine
- Michaël Chaize’s layout mirroring article
- Styling Flex 3 components with Flash Builder 4
- Image Zoom Effect and Animating Filters by Chet Haase
Other Flash Builder 4 related resources
- What’s new in Flash Builder 4
- Using Data-Centric features with Parsley (and other frameworks)
- Test Driven Development with Flash Builder 4 and FlexUnit
- Using Flash Builder’s Profiler
- Moving existing Flex projects from Flex Builder 3 to Flash Builder 4
Enjoy!
Flex and PHP webinar goodies
As I promised at the end of my webinar here I come with the projects I used:
- The starting project created using Flash Catalyst
- The finished project (Flex and PHP project)
- PSD file
You can use the Import > Flash Builder > Flex project wizard to import these two projects into Flash Builder. However, to make the second project work, you need to copy the PHP files from inside the project (you’ll find a folder named eva_services with a bunch of files) to the root of your PHP server. Next you have to create the database (there is an SQL dump inside the same folder) and change the connection credentials from eva_credentials/db.php to match your local settings). Actually you can read more about this in my article on Debugging Flex and PHP projects.
I know that I squeezed quite a lot in my webinar and I had to move quickly between the topics. But you don’t have to worry because you’ll find articles and screencasts below that go into great detail on all the topics I covered:
- Setting up XDebug and debugging Flex and PHP projects here
- Working with Doctrine, Zend Framework, and Flex here
- Working with Flash Builder’s DCD features on PHP projects here
- You’ll find many Flex and PHP articles and videos on the Flex and PHP section of Adobe Developer Connection site,
- If you want to read more about remoting and AMF using Zend Framework or AMFPHP here are two articles I wrote awhile ago: Zend Framework and AMFPHP
- Data Paging using DCD features here
Finally, the recordings for the webinars:
- Erase the Designer to Developer gap: Adding interactions to your design (Serge Jespers’s session)
- Connecting a Flex app to PHP services (my session)
- Connecting a web application to a J2EE backend using Flash Builder 4 (Michael Chaize’s session)
- Working with Flash CS5 components in your Flash Builder 4 project (Mike Jones’s session)
- Going multi-user with P2P in Flash Player 10.1 (Tom Krcha’s session)
- Developing multi-user applications with LiveCycle services (Tom Krcha’s session)
- Bringing web Applications to the desktop with AIR 2 (Piotr Walczyscyn’s session)
- Code once and run on multiple mobile devices (Mark Doherty’s session)
- Rapidly build, deploy, and maintain Internet apps with ColdFusion (Terry Ryan’s session)
Again, I want to thank all of you who took the time to attend my session. Until the next time, Ciao!
Working with Doctrine 1.x, Zend Framework, and Flex
Later Update: If you are looking for an article rather on Doctrine 2 than Doctrine 1, then check this one.
This year I finally had the time to play with Doctrine (version 1.x) and Flex. Actually, it was more than playing; I’m using it for a real project that hopefully will enter production pretty soon. To summarize the experience in just a few words: it’s mind-blowing.
OK, I admit I may be exaggerating a little bit. Still, it is something that can change the way you build projects. Doctrine is an ORM (Object Relational Mapper) framework for PHP and it can really speed up the server side development when you have a lot of tables in your database.
In this article, I explore how to work with Doctrine on the server side, Flex on the client side, and remoting to communicate between Flex and PHP (using the Zend Framework for remoting on the PHP side). I also want to share with you some tools and workflows that can save you some time. While most things are fairly straightforward there are a number of tips and tricks that you may find useful if you decide to go down this road. (I will show you how to use plain vanilla value objects and how to handle dates just to give you two examples. Why reinvent the wheel?)
The application I’m going to build in this article is simple but the workflow is the same one I used with a much more complex application. Having said that let’s start by understanding the big picture.
Installing Flash Builder 4 and Zend Studio 7.1 together on Mac
If you read my blog you know that one of my favorites setups is Flash Builder and Zend Studio installed together on the same Eclipse instance. This is something that you can easily achieve: install Zend Studio and then grab the plug-in version of Flash Builder and start the installer. At some point you can choose the Eclipse installation you want to use (in this case you’ll point to Zend Studio) and you are done.
However, on Mac there’s a catch: for now Flash Builder 4 is available in only a carbon based version while Zend Studio 7.1 is only cocoa based. And these two versions can not be mixed together (we are working on a cocoa version).
Fortunately there is a workaround. My friend, Roy Ganor from Zend, told me you can use the update URL and this way you’ll be able to install the Zend Studio on top of the Flash Builder 4. The update URL is this: http://downloads.zend.com/studio-eclipse/updates/7_1.

Basically, all you have to do is to open Help > Install New Software… click the Add button to add the Zend update site and then click OK. Next you select this newly added site from the combo-box and follow the wizard. Unfortunately, on the last step you may encounter an error like this:
Cannot complete the install because of a conflicting dependency.
Software being installed: Zend Studio Patches Feature 7.1.0.v20091227 (com.zend.php.patches.feature.group 7.1.0.v20091227)
Software currently installed: Eclipse Web Developer Tools 3.1.1.v200908120400-7R77FStEVw2z07WtDz-OZrhL5C-3 (org.eclipse.wst.web_ui.feature.feature.group 3.1.1.v200908120400-7R77FStEVw2z07WtDz-OZrhL5C-3)
Only one of the following can be installed at once:
JavaScript Development Tools Core 1.0.201.v200908101420 (org.eclipse.wst.jsdt.core 1.0.201.v200908101420)
JavaScript Development Tools Core 1.0.201.v2010012803 (org.eclipse.wst.jsdt.core 1.0.201.v2010012803)
Cannot satisfy dependency:
From: Zend Studio Patches Feature 7.1.0.v20091227 (com.zend.php.patches.feature.group 7.1.0.v20091227)
To: org.eclipse.wst.web_core.feature.patch.feature.group [3.1.1.v20091227]
Cannot satisfy dependency:
From: JavaScript Developer Tools 1.1.2.v200908101420-77-FGCCcNBC-BhLcE_Pm (org.eclipse.wst.jsdt.feature.feature.group 1.1.2.v200908101420-77-FGCCcNBC-BhLcE_Pm)
To: org.eclipse.wst.jsdt.core [1.0.201.v200908101420]
Cannot satisfy dependency:
From: JavaScript Developer Tools 1.1.2.v200908101420-77-FGDCcNBDjBXMoBbFb (org.eclipse.wst.jsdt.feature.feature.group 1.1.2.v200908101420-77-FGDCcNBDjBXMoBbFb)
To: org.eclipse.wst.jsdt.core [1.0.201.v2010012803]
Cannot satisfy dependency:
From: WST Web Core 3.1.1.v200908120400-7H77FDAAT7oGlfz0dFV3j0BgbCD7 (org.eclipse.wst.web_core.feature.feature.group 3.1.1.v200908120400-7H77FDAAT7oGlfz0dFV3j0BgbCD7)
To: org.eclipse.wst.jsdt.feature.feature.group [1.1.2.v200908101420-77-FGCCcNBC-BhLcE_Pm]
Cannot satisfy dependency:
From: WST Web Core Patch 3.1.1.v20091227 (org.eclipse.wst.web_core.feature.patch.feature.group 3.1.1.v20091227)
To: org.eclipse.wst.web_core.feature.feature.group [3.1.1.v200908120400-7H77FDAAT7oGlfz0dFV3j0BgbCD7]
Cannot satisfy dependency:
From: Eclipse Web Developer Tools 3.1.1.v200908120400-7R77FStEVw2z07WtDz-OZrhL5C-3 (org.eclipse.wst.web_ui.feature.feature.group 3.1.1.v200908120400-7R77FStEVw2z07WtDz-OZrhL5C-3)
To: org.eclipse.wst.jsdt.feature.feature.group [1.1.2.v200908101420-77-FGDCcNBDjBXMoBbFb]
I got around this error by following these steps:
- install the Zend Studio 7.1.x
- create a folder somewhere on your hard drive and inside of it a new folder named eclipse
- grab the features and plugins folders from the Zend Studio installation folder and copy them to the eclipse folder you’ve created earlier
- go back to your Flash Builder 4 installation folder and inside the dropins folder create a file called emf.link. Add in the emf.link file this line: path=/Users/mcorlan/Documents/work/zend_studio_7.1_plugin – this folder contains the eclipse folder with features and plugins folders (make sure you edit the path according to where you placed the Zend Studio files)
It seems that either Eclipse 3.5.1 made some backward steps when it comes to installing plug-ins that have dependencies or I haven’t discover some of the available features for installing plug-ins.
Debugging Flex and PHP
As your projects grow in size and more people get involved you’ll find yourself fixing more and more bugs. When this happens, one of the best friends a developer has is the debugger. In this paper, I’ll talk about some of the workflows and tools you can use to debug Flex and PHP projects.
If you want to try the steps outlined here for yourself, you’ll need Flash Builder 4, a PHP and MySQL server (MAMP or WAMP will do just fine), Eclipse PDT, and XDebug.
On March 24th I did a webinar on this subject. You can watch the recording over here.
- Installing the sample project
- Using Flash Builder 4 features for debugging
- Debugging the PHP code
- Using XDebug, Eclipse PDT, and Flash Builder 4 to debug Flex and PHP code
- Other techniques
- Where to go from here
Installing the sample project
In this article I’ll use a simple Flex and PHP project that displays data from a MySQL database. The data is retrieved via remoting using the Zend AMF part of the Zend Framework. If you don’t know what remoting is, see Flex and PHP: remoting with Zend AMF.
On the server side I have a simple PHP class (MyService.php) that implements CRUD operations for a single database table. I wrap each record into a PHP data object (VOAuthor.php). On the client side, I have a simple UI for displaying the data (in a data grid) and editing a record (in a form). Most of the Flex client was created using the data-centric development (DCD) features from Flash Builder 4. (For more on DCD, see Working in Flash Builder 4 with Flex and PHP.)
Download the project from here: http://corlan.org/downloads/flex_project.zip.
If you don’t already have Flash Builder 4, download the plug-in or standalone version from here.
[top]
Adding the Zend Framework
As a first step, you’ll need to add the Zend Framework to your server.
- In Flash Builder 4, choose File > New > Flex Project.
- Give the project a name and select PHP for the Application Server Type.
- Click Next.
- On the next screen specify the path to your web root and the root URL.
- Click Finish.
- After Flash Builder 4 creates the project, click Connect to Data/Service in the Data/Services view.
- Select PHP as the Service Type and click Next.
- For the PHP class select a PHP file from your webroot (see Figure 1). For example, if you have a WAMP installation, you should have an index.php file in your www folder.
- Click Finish and a confirmation window opens asking you to install the Zend Framework(see Figure 2). Click OK.
- Another confirmation window will confirm the installation of the Zend Framework. Click OK.
- You can then cancel the Connect to Data/Service wizard and you can delete the project too.
Figure 1. The Connect to Data/Service wizard
Figure 2. Installing the Zend Framework
If you open up your web root folder, you should now see a ZendFramework folder.
[top]
Importing the sample project
You’re now ready to import the sample project.
- In Flash Builder 4, choose File > Import > Flash Builder Project.
- Click on the Browse button and navigate to the flex_project.zip file you downloaded earlier.
- Click Open and then click Finish.
[top]
Setting up the PHP service files
Now that you have the project imported, you’ll need to make some changes in order to make it run.
- Using Explorer (Windows) or Finder (Mac OS X), move the zendamf_remote folder from the project directory to your web root folder.
- Back in Flash Builder 4 delete the zendamf_remote folder.
- Choose File > New > Folder. Click Advanced and then select Link To Folder In The File System. Click Browse and select the zendamf_remote folder from your web server root (see Figure 3).
Figure 3. Creating a linked resource to the zendamf_remote folder
Next you need to define the linked resource to the MyService.php file.
4. In Flash Builder, open the services folder and delete the MyService.php node.
5. Right-click the services folder and choose New > File.
6. Click Advanced and then select Link To File In The File System.
7. Browse to select the MyService.php file from the zendamf_remote folder in your web root folder.
[top]
Setting up the database
Inside the project you’ll find a file called sql_dump.txt. Use this file to create the authors_aut table and to populate it with data.
Next edit the zendamf_remote/MyService.php file and update the credentials used for connecting to the database (at the top of the file you’ll find constants for server host, database name, user, and password).
[top]
Configuring paths
Now you’ll need to configure the paths used by this project for web root and the Zend Framework. In Package Explorer double-click the bin-debug/amf_config.ini file. Edit the following lines and make sure the values point to your web root and Zend Framework. For example, on a Windows machine with WAMP, these lines may look like this (make sure they do not start with “;”):
webroot =C:/wamp/www
zend_path = c:/wamp/www/ZendFramework
[top]
Configuring the output folder
- Lastly, you need to set the output folder of the project.
- Right-click the project name in the Package Explorer and select Properties.
- Select the Flex Server node from the list.
- For the Output Folder add the path to your webroot followed by “\flex_project-debug”.
- On my WAMP configuration the path is C:\wamp\www\flex_project-debug.
- Click Validate Configuration and then Apply and OK.
Figure 4 shows the project after these steps.
Figure 4. The flex_project project in Flash Builder 4.
Now you are ready to run the project (choose Run > Run flex_project). Once the application is loaded in the browser, you should be able to see the records displayed in the data grid and to edit them.
Figure 5. Running the application
[top]
Using Flash Builder 4 features for debugging
There are (at least) three different ways to debug your code using Flash Builder 4 (please note that I use the term debugging here in a broad sense).
Two new views in Flash Builder 4 help you to debug your code: the Network Monitor and Test Operation views. If don’t see these you views you can add them by choosing Window > Other Views and expanding the Flash Builder node (Network Monitor is available only in Flash Builder Premium).
[top]
Network Monitor
Using the Network Monitor view you can see all the communication between the Flex client and the server. You can see both the raw data and the objects. If you want to use it, you must enable it first by clicking on the Enable Monitor icon in Network Monitor view (see Figure 6).
Figure 6. Enabling the Network Monitor
Now, just run the application (you don’t have to run it in debug mode). As you use the application and data are exchanged with the server, you should see each request, how long it took, and all the data that was sent/received (see Figure 7).
Figure 7. Using the Network Monitor
[top]
Test Operation
The Test Operation view, as the name implies, lets you to test the available operations. In Test Operation view, select the getData() operation, and click Test. You should see the four VOAuthor objects (see Figure 8). If the operation expects arguments, then this view lets you define the arguments values.
Figure 8. Using Test Operation
[top]
Flash Builder 4 debugger
The most powerful way to detect bugs is, of course, debugging. The Flash Builder debugger is a powerful tool that can help you quickly pinpoint and resolve bugs.
Let’s see how you can debug the Flex and PHP code. First run the project in debug mode. There are a number of ways to do this:
- If you are in the Flash perspective you can click the Debug toolbar button.
- You can also right-click flex_project.mxml and choose Debug As > Web Application.
- Or, you can choose Run > Debug flex_project.
This will start the debugger. If you set a breakpoint inside the dataGrid_creationcompleteHandler() function and run in debug mode you should see the debugger in action (see Figure 9).
Figure 9. Flash Builder debugger in action
[top]
Debugging the PHP code
What about debugging the PHP code? First of all, you should check that you don’t have errors in your PHP services (classes). You might have misspelled a variable or function name, or used the wrong credentials for connecting to MySQL, and so on. Then, if you add some initialization code and make a call to the method you want to test you can test the execution of the code.
For example, with my setup I could load the following URL in a browser: http://localhost/zendamf_remote/MyService.php .
This is the URL to the PHP service. If there are no syntax errors, then I can check that getData() returns what I expect to by adding this code above the class definition:
$service = new MyService();
print_r($service->getData());
PHP developers have been using a combination of var_dump() and die() for years in order to see what is happening with our PHP scripts. But how can you use this approach when you’re working with Flex and PHP? Instead of just dumping variables on the screen, you can have a logging function that dumps the variables into a text file. For example, I use this function:
function logMe($var) {
$filename = dirname(__FILE__) . '/__log.txt';
if (!$handle = fopen($filename, 'a')) {
echo "Cannot open file ($filename)";
return;
}
$toSave = var_export($var, true);
fwrite($handle, "[" . date("y-m-d H:i:s") . "]");
fwrite($handle, "\n");
fwrite($handle, $toSave); fwrite($handle, "\n");
fclose($handle);
}
Then, if I want to log, for example, the argument that Flex sends when the saveData() method is called, I just add this line inside of the saveData() method, run the Flex application, and edit a row:
logMe($author);
If you try this, you’ll see something like this in the log file (you can find the log file in the zendamf_remote folder):
[10-02-18 14:20:01] stdClass::__set_state(array( 'lname_aut' => 'Corlan', 'fname_aut' => 'Mihai', 'id_aut' => '15', ))
[top]
Using XDebug, Eclipse PDT, and Flash Builder 4 to debug Flex and PHP code
What about actually debugging the code using a PHP and Flex debugger? I think this is by far the most powerful and fast method to pinpoint issues in your application, especially when dealing with client-server applications.
For this part you’ll need some additional tools besides Flash Builder 4: XDebug for debugging the PHP code, and Eclipse PDT used as a client for XDebug (of course you can also use it for editing PHP files).
[top]
Installing and configuring XDebug
You can get Windows binaries of the XDebug from the project website. Unfortunately, if you need it for another platform you have to grab the source and compile it for your platform or look somewhere else. After I searched a little bit, I found that you can find binaries for other platforms at the ActiveState website.
Once you extract the archive for your operating system, you’ll find XDebug versions for different PHP versions. On my machine I’m running PHP 5.2.6, so I used xdebug.so for PHP 5.2.
With my MAMP server I copied the xdebug.so file to /Applications/MAMP/bin/php5/lib/php/extensions/no-debug-non-zts-20050922/ and then I open up the php.ini file (from /Applications/MAMP/conf/php5/) and added these lines at the end of the file:
[xdebug]
zend_extension=/Applications/MAMP/bin/php5/lib/php/extensions/no-debug-non-zts-20050922/xdebug.so
If you have configured the Zend debugger, then you’ll need to comment those lines. Save the php.ini file and restart the Apache server. If you run a phpinfo() script you should see an entry called XDebug.
Next, you need to configure the XDebug. Under the previous lines in php.ini, just add these lines:
xdebug.remote_enable=On
xdebug.remote_host="localhost"
xdebug.remote_port=9000
xdebug.remote_handler="dbgp"
Make sure you match the remote_host with your configuration, and make sure you set a remote_port that it is not used by other applications running on your machine.
Save the file and restart the server.
[top]
Installing Eclipse PDT and Flash Builder 4 together
I like using modern IDEs not only for writing code, but for debugging too. One good client for XDebug is Eclipse PDT (Eclipse PHP Development Tools). You can download PDT from here.
The beauty of using Eclipse-based IDEs is that you can install multiple products together in the same Eclipse environment. In this case, you have two choices: either install the Flash Builder 4 plug-in on top of Eclipse PDT, or grab the update link of Eclipse PDT and install it on top of your Flash Builder 4 standalone installation.
On my machine I chose the first option. If you are on a Mac, you have to grab the Mac OS X Carbon version of Eclipse PDT because Flash Builder 4 is available only for Carbon.
Once you have these two IDEs installed together you can have combined Flex and PHP projects (projects that have both Flex and PHP natures). The easiest way to create such a project is to start with a new PHP project and then apply Flex nature (Right-click the project name and choose Add/Change Project Type > Add Flex Project type. When the wizard starts make sure you select PHP as the application server type.)
Note: the project used for this article was created using this approach, so it has both natures.
[top]
Using XDebug, Eclipse PDT, and Flash Builder
Actually, the hardest part of setting up debugging for Flex and PHP projects is already behind you. The last step is the creation of a PHP debug configuration for your flex_project project.
But first, let’s make some changes in the Eclipse preferences. Open the Preferences for Eclipse and select the Debug option in the PHP node. For the PHP Debugger, select XDebug (see Figure 10). If you specified a port other than 9000 for XDebug in php.ini, then you have to select Installed Debuggers (extend the Debug node) and configure the port for XDebug. Click Apply.
Figure 10. Making XDebug the default option
Next, type browser in the search box of the Preferences window (top-left corner), select the Web Browser entry, and check Use External Web browser option (see Figure 11). This will make Eclipse start the debugging sessions in the default web browser instead of the internal one.
Figure 11. Setting up the external web browser for debugging.
The next step is to create the Debug configuration for PHP. You’ll use this configuration to start the PHP debugger and thus once you start the Flex debugging session, the PHP debugger will connect to the same page. Click the arrow next to the Debug button (see Figure 12) and choose Debug Configurations.
Figure 12. Open Debug Configurations.
In the Debug Configurations dialog box, select PHP Web Page node from the left panel, and double-click it to create a new configuration. Type flex_project_php as the name, and then select XDebug as the Server Debugger option (see Figure 13). For the File entry select the MyService.php file from flex_project/zendamf_remote/MyService.php. Deselect the Auto Generate checkbox in the URL section, and for the URL, type the URL that points to the MyService.php file (on my machine this URL is http://localhost/zendamf_remote/MyService.php). Click Apply and then click Debug.
Figure 13. Creating the PHP debug configuration
Now that you have started the PHP debugger, place a breakpoint inside of the dataGrid_creationCompleteHandler() function from flex_project.mxml, and place another breakpoint in the flex_project/zendamf_remote/MyService.php inside of the getData() method.
Then run the Flex application in debug mode (with the Flash perspective selected, right-click flex_project.mxml and choose Debug As > Web Application). Once the application is launched in the browser you should see the Flex debugger in action and the code execution halted at the breakpoint from the dataGrid_creationCompleteHandler function (see Figure 14).
Figure 14. Flex debugger in action
Resume execution (or press F8) and you should see the PHP debugger stopped at the first line of flex_project/bind-debug/gateway.php. This is the script called by the Flex client when it uses remoting to call the MyService class. This script sets up some configuration parameters such as where the Zend Framework is installed, and then starts the Zend AMF remoting. After using Resume, you should hit the breakpoint from the getData() method of the MyService object (see Figure 15).
Figure 15. PHP debugger in action
Once you’ve done with the debugging in PHP, click Terminate (the red square button) to terminate the PHP debugging session.
[top]
Other techniques
Some people use tools like proxy sniffers (such as Charles) or Firebug to see the communication between the client and the server. These tools understand the AMF3 format, the messaging format used by remoting.
While there is nothing wrong with this approach, I feel that the new features of Flash Builder 4 (Test Operation and Networking Monitor) provide similar functionality but in an integrated package.
[top]
Where to go from here
Using Flash Builder 4 for Flex and PHP projects provides a great foundation. Add XDebug and Eclipse PDT to this and you have an even more powerful combination for development and debugging. As your projects grow in scope and complexity, you will be able to debug the Flex and PHP code more easily and at the same time.
Visit the Flex Developer Center – Learn Flex and PHP page for more articles on Flex, PHP, and AMF. And of course keep an eye on my blog. More Flex and PHP articles will come.
[top]
Quick poll on debugging and tooling for Flex and PHP projects
As you know, one of my focuses as a Platform evangelist is Flex and PHP integration. Thus you can imagine I spend quite a lot of time doing Flex and PHP projects or research around these technologies. Lately I’ve been working on workflows for PHP and Flex (tooling, debugging, libraries) in light of the new tools (or new versions) we have been developing at Adobe. While some of these findings will see the light as articles, others are more intended as suggestions or feature request for upcoming versions of Flash Builder.
I’m really curious to find out:
- What tools are you using?
- What do you use for debugging?
- What frameworks (AMFPHP, Zend Framework, Doctrine etc) do you use when working on Flex and PHP projects?
- And the most important question: What features do you think Flash Builder needs in order to make you a happier/richer developer?
Please take some time and drop a comment with your thoughts around these questions.
And because I understand it takes some time to answer these questions, I want to give away three Flash Builder 4 licenses. I will choose randomly three lucky people from those who take the survey. The winners will be announced at the end of March, however you’ll get the licenses once we release Flash Builder 4 (now it is in Beta 2). Make sure you fill in your real name and a valid email address.
LATER EDIT: The winners of this raffle are: Mario Kralj, chandra shekhar pant, and Ben Dalton! Congratulations and pretty soon you’ receive the license.
Flex для PHP-разработчиков
Я работал с веб-технологиями, начиная с ранних 90-х, и моей первой серверной технологией был язык PHP. Потом я работал с ColdFusion и Java, но всегда считал себя PHP-разработчиком. Когда пришел AJAX, я начал работать с фреймворками типа Prototype и script.aculo.us, и начал создавать собственные фреймворки.
В конце 2006 года я впервые попробовал разработку на Flex. Это было что-то вроде экспресс-курса, так как у меня было от 4 до 6 недель на создание демо-приложения для выходящей вскоре версии FDS (Flex Data Services, теперь называются LiveCycle Data Services). Хотя я был новичком во Flex и FDS, проект пошел хорошо, и я действительно насладился разработкой и процессом изучения.
Тем не менее, как бы приятно это ни было, это было нечто другое. Я имею в виду, что, когда я делал веб-приложения на ColdFusion или Java, я не ощущал большой разницы в сравнении с PHP; это было больше вопросом поиска правильных API и усвоения специфики языка. Позже, когда я начал работать с AJAX для DHTML, это тоже не так сильно отличалось. Большая часть сайта создавалась с помощью все тех же техник серверного языка, нужно было просто добавить специй тут и там (в данном случае – некоторых AJAX- виджетов).
Когда я сделал свой первый проект на Flex, о, мой мальчик, это было такое переключение! Четкое разделение между клиентом и сервером (бизнес-логика на стороне клиента в дополнение к бизнес-логике на стороне сервера), клиентская технология, которая компилировалась, а не интерпретировалась, два языка на клиенте, и все это требовало другой настройки ума, чем традиционная веб-разработка.
Это и есть моя причина для написания этой статьи. Я хочу поделиться с вами некоторыми из особенностей Flex относительно PHP. Вместе с этим, я хочу представить Flex, сравнивая его с PHP там, где такое сравнение имеет смысл. Итак, эта статья предназначена для:
- PHP-разработчиков, которые хотят узнать о Flex и ActionScript 3 больше, чем может дать простое определение;
- PHP-разработчиков, которые уже сделали свои первые попытки кодирования Flex-приложений и хотят более широкого и глубокого понимания
Чего нет в этой статье? Мое намерение не в том, чтобы превратить вас во флексеров, и не в том, чтобы убедить вас в превосходстве Flex над X или Y. Я твердо верю, что существуют различные типы проектов, и что они могут и должны быть реализованы с помощью различных инструментов. Когда производительность, максимальная отдача от инвестиций и удобство являются главными приоритетами, то нет такой вещи, как универсальный инструмент.
В то же время, эта статья не является полной документацией к Flex или ActionScript3. Существуют десятки книг, охватывающих эту тему сотнями страниц. Есть тысячи статей о Flex. Моя цель – дать вам достаточно информации по наиболее важным темам и там, где это имеет смысл, связать концепции Flex с аналогичными понятиями из PHP. Чтобы статья была полезной, я структурировал ее и постарался не вдаваться слишком глубоко в детали. В конце я даю краткое введение в Adobe AIR и ссылки на дополнительные ресурсы, если вам нужна подробная информация по этим вопросам.
Для большинства примеров я выбрал Flex 3, на то есть пара причин. Во-первых, во время написания этой статьи Flex 4 все еще не вышел. Во-вторых, Flex 4 в основном является эволюцией Flex 3, так что большая часть описываемых вещей может быть применена к Flex 4 с минимальными изменениями, если они вообще понадобятся. В некоторых случаях я укажу на эти отличия. Что касается PHP, то я использую версию PHP 5.3. Теперь посмотрим содержание, а затем – погрузимся в материал!
- Что такое Flex?
- Введение в язык MXML
- Введение в язык ActionScript 3
- Flex асинхронен
- Связывание данных, метаданные и отражение
- Где мои данные, давайте их сюда!
- Аутентификация пользователя во Flex- и PHP-проектах
- Работа над проектами Flex и PHP
- Что такое Adobe AIR?
- Что будет с Flash дальше??
- Куда направиться после всего этого
Что такое Flex?
Простейший ответ: Flex – это просто еще один способ создания Flash-приложений. Flex-приложение компилируется в SWF-файл, который проигрывается в браузере с помощью Flash Player. Но зачем нужен еще один способ создания Flash-приложений? Традиционно Flash-приложения создавались в среде разработки Flash. Если вы посмотрите на нее, то вы заметите, что она ориентирована в основном на дизайнеров. Там есть сцена, временная шкала, инструменты рисования и т.д.
При разработке приложений важную роль играет производительность, вам нужны компоненты, вы хотите максимально упростить разработку, использовать код повторно, и, не в последнюю очередь, вы хотите современную IDE – интегрированную среду разработки.
Так что пересмотренный ответ может быть таким: Flex – это фреймворк с открытым исходным кодом, помогающий разработчикам быстро создавать насыщенные интернет-приложения (RIA, Rich Internet Applications), работающие внутри Flash Player. Фреймворк к сегодняшнему дню хорошо отточен в сравнении со своим первоначальным состоянием в 2006 году, когда вышел Flex 2, Flash Player 9 и ActionScript 3.
[top]
Flex: два языка и один фреймворк, чтобы их связать
Под крышей Flex на самом деле можно найти вот что:
- Два языка: MXML и ActionScript 3. Flex предлагает два языка для разработки приложения. В следующих главах я углублюсь в каждый из них.
- Богатая библиотека компонентов.
- Компиляторы и отладчик.
- Инструменты командной строки для компилирования и отладки приложения Flex.
Так как Flex является фреймворком с открытым исходным кодом, то я призываю вас сходить на домашнюю страницу этого проектаhttp://opensource.adobe.com/flex и скачать SDK. Вы можете увидеть исходный код всех компонентов библиотеки, может проверить открытую базу данных багов и фич (http://bugs.adobe.com/flex), и вы можете увидеть страницы вики со спецификациями.
Частично высокая продуктивность Flex обеспечивается большой библиотекой компонентов. Там есть все мыслимые UI-компоненты (поля ввода, панели, окна, слайдеры, датагриды, комбобоксы, аккордеоны, табуляторы…) Есть контейнеры для разметки и элементы форм. Ниже вы увидите скриншот с доступными компонентами Flex 3 (кликните, чтобы увеличить).
И если этих компонентов вам недостаточно, то вы можете создать свои или расширить существующие, так как у вас есть доступ к исходным кодам.
[top]
Почему стоит знать про Flex
Прежде, чем углубиться в изучение, давайте сделаем паузу и вернемся к причинам, по которым вам может быть интересен Flex.
Традиционные HTML веб-приложения имеют архитектуру «запрос-ответ». Браузер отправляет запрос, а сервер посылает в ответ страницу, и этот цикл повторяется. HTML и CSS – отличный выбор для представления информации, возможно, один из лучших. Но с годами эта архитектура вышла за рамки простого статического представления информации и стала платформой для приложений. С помощью скриптовых технологий нам удалось создать динамические страницы и общаться с сервером с помощью более узких и конкретных запросов. Кроме того, добавив, DHTML и AJAX, мы вдохнули новую жизнь в обслуживаемые сервером страницы: пользователь может работать с загруженной страницей и изменять ее вид без необходимости обновления всей страницы.
С развитием технологий появились более сложные приложения. Некоторые веб-приложения начали повторять полнофункциональные приложения для настольных ПК, и в то же время сохранили удобство веба: они доступны отовсюду, где есть браузер и подключение к Интернету. Так появились онлайновые версии электронных таблиц и текстовых редакторов.
Однако, с точки зрения юзабилити, Интернет-приложения были не так дружелюбны к пользователю, как настольные. В то же время, для создания этих сложных веб-приложений нужно владеть многими технологиями (JavaScript, DHTML, CSS, AJAX-библиотеки, серверные технологии) и иметь опыт обхода различий между браузерами и тем, как они рендерят HTML/CSS/JS.
Так в 2002 году Macromedia ввела термин RIA (Rich Internet Applications) для описания нового поколения приложений, сочетающих преимущества настольных и веб-приложений. Технология Flash Player сделала это возможным.
В общем, если вы хотите создать приложение (не только сайт или веб-страницу), то можно сделать это с помощью Flex. Некоторые вещи просто невозможны в HTML/JavaScript, другие очень сложно реализовать одинаково для всех браузеров. Flash Player предлагает одну из лучших графических систем, он установлен на 98% подключенных к Интернету компьютеров и хорошо работает со звуком и изображениями. Он поддерживает микрофоны и веб-камеры, потоковое воспроизведение и обмен данными, прекрасно работает с типографикой, и этот список можно продолжить.
Взгляните на три приложения, дающих представление о возможностях Flex:
- SumoPaint бесплатный графический редактор
- Mindomo приложение для составления ментальных карт (MindMaps)
- Times Reader читалка для The New York Times
В то же время другие технологии вошли в сферу RIA. Кроме AJAX-улучшений, сделавших возможными такие приложения как Gmail или Google Spreadsheets, сегодня мы имеем также Silverlight от Microsoft и JavaFX от Sun.
[top]
От тонкого клиента – к умному и богатому клиенту
Давайте вернемся к браузерам и тому, как поставляются веб-приложения. Когда браузер отправляет запрос, сервер использует для подготовки страницы комбинацию статического контента (HTML/CSS/JS кода) и скриптов, которые могут сделать запрос к базе данных или вызвать другие скрипты, а в итоге дают HTML/CSS/JS. Эта страница загружается и отрисовывается браузером. Ключевой момент в том, что обычно эта страница (или ответ) содержит визуальную разметку вместе с представляемыми данными.
Когда нужно показать новое состояние приложения, браузер делает новый запрос, и сервер подготавливает новую страницу. Клиент снова просто показывает результат, полученный с сервера.
Flex-приложения работают по другому. Сервер отправляет готовое Flex-приложение (файл SWF), работающее внутри браузера в плагине Flash Player. Как правило, этот SWF-файл содержит только бизнес-логику на стороне клиента. Если нужны данные (из базы данных, например), Flex-приложение запрашивает их. Сервер возвращает данные (в формате XML, JSON или AMF3), а клиент сам знает, как представить их визуально. В этом случае мы имеем сервис-ориентированную архитектуру: Flex-приложение является клиентом, который может использовать сервисы поставки данных. Приложение может изменить свое состояние без перезагрузки страницы или перезагрузки SWF-файла в браузере. Приложение является клиентом, который может больше, чем просто показать результат с сервера. Таким образом, используя Flex и Flash Player, можно создать почти любое приложение для Интернета, от игр и виджетов до больших веб-приложений для редактирования любого вида контента и многое другое.
Но довольно сухой теории, давайте посмотрим код!
[top]
Введение в язык MXML
MXML – это декларативный язык, основанный на XML. В приложении Flex язык MXML используется для быстрой разметки структуры и внешнего вида. Во Flex все, что можно сделать с MXML, можно также сделать и с ActionScript 3, но обратное не верно.
Но если в ActionScript 3 можно сделать все то же, что и в MXML, то зачем тогда нужен MXML? Потому, что обычно намного проще читать код интерфейса пользователя, описанный с помощью XML-языка, чем описанный с помощью языка императивного, такого, как AS3. Так для описания интерфейса используется меньше кода. Кроме того, намного проще создавать инструменты для декларативных языков, чем для императивных. Вот приложение “Hello World!” на MXML:
1: <Label text="Hello World!" fontSize="14" color="red" x="100" y="50"/>
В этом коде я использую Flex-компонент Label (Метка) для показа текста на экране. Я задаю атрибуту text тот текст, который нужно показать. Кроме того, я хотел слегка настроить внешний вид и положение этой метки на экране. Для этого я использую атрибуты 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);
Здесь у меня семь строк кода, чтобы делать то же самое, что я сделал одним тэгом с атрибутами в MXML! Теперь представьте, что в реальных приложениях есть много элементов управления, которые сгруппированы в различных контейнерах. Гораздо легче поддерживать код, написанный с использованием MXML, чем код в виде сотен строк на ActionScript 3.
Хотя вы можете использовать MXML для описания приложения, вы не можете использовать его же для реализации бизнес-логики. Для этого используется ActionScript 3.
Flex-приложения запускаются во Flash Player, а он понимает только ActionScript 2 и ActionScript 3. Это означает, что любой MXML-код вашего приложения должен быть преобразован компилятором MXML в код ActionScript 3. А уже этот код потом преобразуется компилятором ActionScript в байт-код (файлы SWF), которые могут быть поняты Flash Player.
Таким образом, за почти каждым компонентом MXML стоит ActionScript-класс (но некоторые MXML-тэги не имеют соответствующих им классов ActionScript, это такие тэги, как Script и Model). Например, вот отрывок из класса Label:
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: }
В любом 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, и здесь же определяются пространства имен. В данном случае у меня только одно пространство имен для языка и Flex MXML-компонент: mx. Это код для Flex 3, а во Flex 4 есть небольшие отличия – в этом месте объявляется больше пространств имен.
Если вы пишете свои собственные компоненты, то вам придется добавить пространства имен и для них. Вот, к примеру, я объявляю второе пространство имен для обозначения всех созданных мной компонентов (в этом примере я использую собственный компонент метки под названием MyCustomLabel):
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-сайта различные состояния, как правило, реализуются в разных страницах. Приложение Flex очень похоже на приложения для рабочего стола. Это означает, что вы можете использовать один MXML- файл для отображения в одной странице различных состояний приложения. Flex предлагает несколько способов сделать это с помощью компонентов, таких, как аккордеон, навигатор по вкладкам (Tabsets), разметка типа «Карточка», а также с помощью флекс-модулей.
Вы видели, что в MXML-коде можно определять внешний вид приложения. Но вы также можете использовать его для создания своих компонентов путем расширения уже существующих. Посмотрим на примере. Предположим, что в вашем приложении есть множество форм, имеющих две кнопки: Сохранить и Отменить. Взгляните на код этого 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>
При создании собственных компонентов можно выбрать расширяемый компонент (в MXML нельзя расширять Application). Я решил расширить HBox (горизонтальный ящик) – это контейнер, отображающий всех своих потомков в одну строку. Внутрь контейнера я добавил две кнопки, одна для сохранения и еще одна – для отмены. Также я задал каждой кнопке атрибут id. Используйте значение id в качестве ссылки на объект из других частей кода. Это то же самое, что и объявление переменных в коде ActionScript.
Посмотрим, как можно использовать этот компонент в приложении:
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>
Ниже показано, как выглядит приложение:
Вы можете подумать, что в MXML можно использовать только визуальные компоненты Flex (то есть компоненты, отображающиеся на экране). На самом деле это не так. Есть также MXML-тэги для представления и хранения данных и компоненты для обработки данных, они могут получать и отправлять данные с/на сервер. Ниже показан пример общего компонента Object со свойством name:
1: <mx:Object id="myObj" name="Mihai Corlan"/>
Как я сказал ранее, все (или почти все) компоненты Flex имеют соответствующий класс ActionScript, реализующий отображение (если таковое имеется) и логику. Когда вы выбираете ActionScript вместо MXML для создания своего компонента (будь это визуальный компонент или нет), то вы должны иметь в виду, что существует ограничение: конструктор класса должен иметь возможность вызова его без аргументов (а если есть аргументы, они должны иметь значения по умолчанию).
[top]
Смешивая MXML и ActionScript 3
Возвращаясь к своему компоненту FormButtons (тот самый, с двумя кнопками), можно заметить проблему: а что делать, если нужно использовать этот компонент в таком месте, где кнопки «Сохранить» и «Отмена» не имеют смысла? Нужно ли создавать еще один специальный компонент с другими нужными надписями (скажем, «Показать» и «Скрыть»)? Конечно, это вариант, но он плохо масштабируется и это не элегантно! Что действительно хотелось бы, так это компонент более общего плана и способ его настройки. Вот почему рано или поздно вам придется писать ActionScript-код в дополнение к коду на MXML.
В следующем примере я добавил код ActionScript внутрь MXML-кода компонента для того, чтобы задать две переменные для хранения них надписей на кнопках. Обратите внимание, что я использую новый тег, Script, а внутри него – CDATA. Это потому, что внутри XML-документа символы >, < и & недопустимы, если они не представлены как escape-последовательности, а в нашем 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-приложения, использующего этот компонент. Вот код обновленного приложения, использующего новый вариант компонента:
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-код для написания функций, которые будут вызываться по нажатию на кнопку.
Есть еще один способ добавления ActionScript-кода в MXML. Можно создать ActionScript-файл (в этом примере – файл с именем buttons.as) и включить этот файл в файл MXML. Это делается путем добавления тега Script с атрибутом source, указывающим на 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-класс. В этом случае я получу класс c названием FormButtons (потому что это имя файла, и оно используется в качестве имени класса), расширяющий компонент HBox (потому что я выбрал HBox в качестве корневого узла компонента). И все ActionScript-коды внутри класса становятся членами класса: переменные (например, те, что в примере) становятся переменными экземпляра класса, а функции становятся методами этого экземпляра.
[top]
Стили CSS
Теперь поинтересуемся, как можно изменить внешний вид визуальных компонентов Flex. Есть ли что-то вроде CSS для HTML? Да, Flex поддерживает CSS. Во Flex 4 поддержка CSS расширена, чтобы позволить определять стили не только для имен классов, но и для идентификаторов (id), а это делает возможными псевдо-селекторы (например, для кнопки (Button) есть селектор down, over и т. д.) и многое другое.
Как и в 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>
Я создал CSS-класс Button1, в нем определяется цвет надписей и размер шрифта. Затем я задал стиль первой кнопки с помощью ее атрибута styleName. Приложение теперь выглядит следующим образом:
CSS-стили могут быть изменены во время выполнения программы (после того, как Flex-приложение загрузилось в браузер), и внешний вид приложения сразу изменится.
Во Flex 4 Adobe добавила новый язык, называемый MXML для графики -FXG, который добавляет графические примитивы, эффекты, маски и 2D-преобразования. Можно создавать класс скина (кожи) в MXML-файле, используя эти новые теги, а затем назначить этот класс компоненту, который нужно обеспечить скином (кожей). Ниже показан скинованый список Flex 4. Слева показан список в состоянии по умолчанию, а в правой части – состояние при наведении мыши (hover). Можно увидеть приложение в действии здесь.
Блуждая по документации настройки вида Flex-приложений, вы можете встретить термин “skinning” – скинование, он относится к процессу создания скинов – то есть кожи, или шкурки компонента. Изменять внешность компонента можно как чисто графическими скинами, так и с помощью программного скинования. Вот хорошая статья на эту тему.
[top]
Изменение MXML-кода во время выполнения
Иногда нужно изменить компоненты интерфейса во время выполнения, «на лету». Например, вы хотите, в зависимости от полученных с сервера данных, построить на лету форму. И снова, чтобы сделать это, вы можете использовать код ActionScript. Любой визуальный Flex-компонент имеет методы для добавления нового дочернего элемента, его удаления, получения всех дочерних элементов, и т.д. Если вы хотите, можно сравнить это с тем, как изменяется DOM в HTML с помощью JavaScript. Тем не менее, есть отличие: в JavaScript вы можете включить полученный с сервера HTML-код (вызовом AJAX). Во Flex это невозможно, и функции eval() во Flex нет. Тем не менее, есть способ загрузки других Flex-приложений или Flex-модулей после загрузки основного приложения.
Если вы знаете наперед все возможные состояния компонента, то можно использовать States (состояния) в MXML для реализации всех состояний одного и того же компонента. Состояния – это та область, где Flex 4 значительно улучшил реализацию Flex 3, сделав работу с состояниями значительно легче и мощнее. Во Flex 4 состояния работают так:
- Вы определяете некоторое количество состояний и задаете состояние по умолчанию;
- Вы можете указать, в каком состоянии должен появиться конкретный компонент;
- Вы можете указать отдельные значения для любого атрибута для каждого состояния, в котором появляется компонент.
Предположим, вы хотите создать компонент, реализующий функцию авторизации в приложении. Вы хотите использовать этот компонент для отображения формы логина, и когда пользователь вошел удачно, вы хотите показать кнопку выхода и имя пользователя. Вот как вы можете создать компонент Login/Logout во 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>
Этот код должен быть понятен сам по себе. В качестве главного контейнера я использую компонент Group, который имеет горизонтально-ориентированную разметку HorizontalLayout (это дает тот же эффект, что и использование контейнера HBox в примере для Flex 3, приведенном выше). Я определил доступные состояния для этого компонента в начале файла. Затем я добавляю три кнопки, текстовые поля ввода и метку. Обратите внимание на атрибут includeIn, указывающий, в каких состояниях появляется компонент. Также есть атрибут excludeFrom для указания состояний, из которых компонент исключается. Если вы хотите, чтобы кнопка была во всех состояниях, то не указывайте ничего в этих ее двух атрибутах. И, вы также можете видеть, что я присвоил выражение атрибутам click обеих кнопок. Например, click=”{currentState=’logged’}” говорит Флексу, что, когда кнопка нажата, нужно изменить состояние компонента на состояние с именем logged.
Я включаю все больше и больше кода ActionScript в эти примеры, хотя я все еще говорю о языке MXML. Это знак к тому, что пришло время приступить ко второму языку Flex, языку ActionScript 3.
[top]
Введение в язык ActionScript 3
ActionScript 3 – это динамический, объектно-ориентированный язык сценариев, являющийся (почти) типо-безопасным (type-safe). ActionScript 3 основан на спецификации ECMAScript 3 (ECMA-262). Также, некоторые его возможности идут в ногу со спецификацией ECMAScript 4. Я думаю, что легче всего объяснить ActionScript 3 тем, кто с ним совершенно незнаком, следующим образом: ActionScript выглядит как смесь языков JavaScript и Java, плюс его собственные яркие черты. На самом деле, JavaScript как язык также основан на спецификации ECMAScript, так что для него это естественно – иметь общее с ActionScript.
Как я сказал ранее, Flash Player может работать с двумя языками: ActionScript 2 и ActionScript 3. Внутри он использует для этих двух языков две разные виртуальные машины (ActionScript 3 и виртуальная машина AVM2 появились во Flash Player 9). ActionScript 3 состоит из основного языка (ключевые слова, типы данных, и т.д.) и прикладного программного интерфейса Flash Player API (этот API дает разработчикам доступ ко всем возможностям Flash Player через API дисплея, 3D API, API рисования, анимации, и т.д.) В этой статье я сфокусируюсь на основном языке. Вот хорошая вводная статья в ActionScript 3.
С этого места я буду использовать для термина “ActionScript 3” аббревиатуру “AS3”.
[top]
Разделение выражений
В PHP для разделения выражений или обозначения их конца используется точка с запятой (;). В AS3 можно использовать точку с запятой (;) или просто символ конца строки. Должен сказать, что когда я вижу код без использования точки с запятой, то мои глаза получают мало удовольствия. Так что лучше использовать тот же символ точки с запятой, что и в PHP.
[top]
Типы данных, переменные, константы
В PHP есть такие типы данных: Булевы (Boolean), целые числа, числа с плавающей точкой, Строки (String), Массивы (Array), Объекты (Object), Ресурсы (Resources) и 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 обозначают отсутствие данных, тем не менее, между ними есть отличие. Когда вы объявляете переменную и не инициализируете ее, она будет иметь значение null, если это не переменная типа Boolean, int, uint или Number. Если у переменной нет типа, и она не инициализирована, она будет иметь значение undefined. В то же время, когда у вас есть динамический объект, и вы хотите убедиться в том, что конкретное свойство или метод определены, то вы можете проверять на значение undefined.
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 предупредит вас об этой ошибке.
Без указания типов вы могли бы получить ошибку уже при выполнении, когда вы или конечный пользователь работаете c приложением, и в этом случае причину дефекта было бы найти намного труднее.
Вторая причина для того, чтобы придерживаться указания типов – это способность компилятора AS3 делать оптимизации, если он знает конкретные типы переменных.
В PHP вы можете изменять тип переменной при каждом присвоении:
1: $myVar = 12; //it is an int
2: $myVar = "now is a string";
В AS3 вы можете сделать то же самое (в strict-режиме) только, если объявляете переменную нетипизированной, используя тип “*”:
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 вы используете оператор “.” (точка), а в AS3 используется “+” (плюс):
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 вы можете иметь процедурное программирование, то есть не объявленное как часть функции:
1: <?php
2:
3: $a = 1;
4: for ($i=0; $i<100; $i++) {
5: $a += $i * $a;
6: }
7:
8: ?>
В AS3 вы не можете оперировать переменными за пределами функций (хотя за пределами функций можно объявить переменные) с одним исключением, которое я опишу, когда буду объяснять классы. Поэтому, если вы попробуете выполнить следующий код, то получите ошибку при компиляции приложения:
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 для того, чтобы сослаться на текущий объект, но вы могли применить ту же технику для любого объекта. Я остановлюсь подробнее на этой теме, когда речь пойдёт о динамических классах.
[top]
Функции и анонимные функции (замыкания)
В 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) c явными аргументами, размещая оператор 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 можно создавать анонимные функции (или замыкания, closures). В предыдущем образце кода представлен пример создания анонимной функции внутри giveMeAFunction() и ее возврат.
Возможно, самая большая разница между функциями в AS3 и PHP это то, как вы определяете их. В PHP вы можете определить в файле любое количество функций. В AS3 вы можете определить только одну функцию в файле, и имя функции должно соответствовать имени файла. Например, если вы определяете функцию doSomeMath(), вам придется создать эту функцию в файле с именем doSomeMath.as. Для определения функций объявляйте пакет (о пакетах вы узнаете в следующем разделе). Поэтому, при создании серии функций-утилит, если вы не хотите писать их в виде множества файлов, можете создать единственный класс и определить эти функции, как статические методы.
[top]
ООП: Классы и интерфейсы
Самое время приступить к ООП (Объектно-Ориентированное Программирование, Object Oriented Programming) особенностям PHP и AS3. В PHP вы можете писать в ООп или процедурном подходе; AS3 ориентирован на объекты.
Начнём с простого PHP-класса, чтобы увидеть отличия в синтаксисе (не забывайте, что я использую PHP 5.3):
1: namespace org\corlan {
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 org\corlan\SimpleClass();
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();
Вот главные отличия:
Название файла класса:
- В PHP можно определить класс в файле с произвольным именем;
- В AS3 имя файла должно совпадать с именем класса (если класс имеет название SimpleClass, то файл должен называться SimpleClass.as ).
Namespace против Package, или пространства имен против пакетов:
- В PHP вы можете использовать пространства имен во избежание конфликта имен между классами;
- В AS3 используются пакеты; однако, когда вы объявляете класс, который находится в пакете org.corlan, это означает, что класс будет внутри каталога org/corlan в каталоге исходников Flex. Имя пакета совпадает со структурой каталогов. Пакеты, используемые совместно с модификаторами доступа к классу могут скрыть данный класс от классов за пределами проекта (об этом позже).
Выражение require/includes против import:
- В PHP обычно вы включаете файл класса, используя функцию require_once. Начиная с PHP5 можно определить функцию __autoload() и вызывать require_once или include_once в этой функции вместо написания списка нужных файлов в начале каждого файла;
- В AS3 для включения нужного класса используется выражение import. Если нужно включить все классы в пакете org.corlan, то можно импортировать весь пакет: import org.corlan.*. Еще одно отличие в том, что компилятор AS3 включает только те классы, которые были использованы в вашем коде (то есть только тогда, когда фактически создается экземпляр конкретного класса).
Вызов метода/члена экземпляра:
- В PHP используется оператор “->” ;
- В AS3 используется оператор “.” (dot – точка) оператор.
А теперь – о модификаторах доступа классов, методов и членов.
Начнем с модификаторов доступа к классам:
- В PHP есть модификаторы final и abstract; модификатора public нет, в PHP все классы – публичные.
- В AS3 есть модификаторы public, internal, final и dynamic. Если вы не указываете модификатор доступа (public или internal), то класс по умолчанию определяется, как internal, а это значит, что он доступен только для классов того же пакета; рublic и final имеют то же значение, что и в PHP; модификатор abstract в AS3 отсутствует, но вы можете обойти это ограничение, используя интерфейсы. Модификатор dynamic помечает класс как класс, который может быть изменен во время выполнения путем изменения существующих членов или добавления новых.
Модификаторы свойств класса:
- PHP имеет: public, private, protected, static
AS3 имеет те же модификаторы что и PHP плюс internal. Internal используется для того, чтобы сделать свойства доступными только изнутри того же пакета. Когда модификатор не указан, используется internal.
Модификаторы для методов класса:
- В PHP: public, private, protected, static, final и abstract.
- В AS3: public, private, protected, static, final, internal и override. Abstract не существует в AS3; internal делает методы доступными только для кода из того же самого пакета.
В AS3 можно делать с методами класса все то же самое, что можно делать с замыканиями функций.
Конструкторы в PHP могут быть помечены как частные (private), можно определить конструктор с тем же именем, что и у класса, а можно использовать специальные методы __construct(), __destruct(). В AS3 конструктор всегда публичный и должен иметь то же имя, что и у класса. Если конструктор не указан, 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: }
Оператор this:
- В PHP используется специальная переменная класса $this, для того, чтобы ссылаться на членов класса (переменные и методы) в пределах того же класса: $this->myVar = 22;
- В AS3 используется тот же this: this.myVar = 22; однако, вы можете пропустить this и использовать myVar = 22.
В AS3 только один класс может быть объявлен внутри пакета (и этот класс дает имя файлу). Однако, за пределами пакета вы можете объявить столько классов, сколько хотите:
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 нельзя объявить конструктор как приватный? Отлично, тогда используя технику, подобную этому примеру, можно убедиться в том, что есть только один экземпляр класса Foo. Если какой-то внешний код вызовет конструктор, появится исключение времени выполнения, потому что внешний код не может использовать экземпляр Bar, так как этот класс невидим к внешнему коду.
Наследование
Расширение классов в AS3 очень подобно расширению в PHP. Используется то же ключевое слово extends, а после него обозначается имя расширяемого класса. Перекрытие делается так же, как и в PHP, разница только в том, что вам придется добавить ключевое слово override к сигнатуре метода. Перегрузка не поддерживается (нельзя иметь два метода с одинаковыми именами).
В 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 class\n";
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 class\n";
30: parent::displayVar();
31: }
32: }
Обратите внимание на то, как класс инициализируется в AS3. Когда создается экземпляр класса, то сначала инициализируются все свойства, затем выполняется статический код, определенный на уровне класса (это именно то, что невозможно в 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 вы можете создать объекты из замыканий функций, используя свойство функции prototype (это подобно привычной в 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-языке геттеры и сеттеры обычно используются для управления теми свойствами класса, которые вы хотите сделать видимыми снаружи. PHP – не исключение. Однако AS3 имеет специальную поддержку свойств с помощью ключевых слов get и set. Вот пример:
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;
В общем, хотя у меня есть геттер и сеттер для поля _salary, я могу обратиться к этим методам, как будто бы они были полями или свойствами, а не функциями: object.salary = 20 вместо object.salary(20). И если вы определите только геттер, то получите свойство, доступное только для чтения. Это я и делаю со свойством _income.
Эта особенность, кроме того, что делает код немного чище, также упрощает написание программных интерфейсов приложения или классов, которые будут использоваться другими, а особенно – фреймворков и библиотек. Представьте, что в своем примере я создал поле _salary как публичное. Если позже я решил бы, что мне нужно проверять задаваемые значения, то мне пришлось бы добавить сеттер. В PHP это выглядело бы как myObject.setSalary(). В этот момент любой код, использующий мой класс, сломался бы; его пришлось бы обновлять для использования с моим сеттером.
В AS3 можно начать писать класс, определив публичное свойство как public var salary:int, а затем, когда вы решите, что сеттер необходим, можно переименовать переменную и добавить публичный метод public function set salary(). Любой код, использующий этот класс, не пострадает от этих изменений, потому что он по прежнему работает со свойством, используя тот же синтаксис: objectInstance.salary = 10.
Существует договоренность – добавлять подчеркивание к имени переменной при использовании этого стиля геттеров и сеттеров в AS3.
Интерфейсы
Интерфейсы в AS3 работают почти так же, как и в PHP. Отличие в том, что, хотя в PHP можно определить методы и константы, а в AS3 можно определить только методы. Однако, можно определить сеттеры и геттеры:
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");
Error – это класс верхнего уровня для всех ошибок в AS3. Расширяя этот класс, вы можете создать свои собственные ошибки, а можете использовать существующие подклассы ошибок.
Приведение типа объекта и его проверка
Иногда нужно привести объект к другому типу или проверить тип. Для проверки типа в 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);
[top]
Область видимости переменной
Посмотрев, как переменные, функции и классы работают во Flex и AS3, нужно поговорить об области видимости переменных. В PHP в основном у вас есть две области: глобальная (переменные определены на уровне файлов) и локальная (переменные определены внутри функции).
Во Flex существует пять возможных областей: тело функции, тело метода экземпляра, тело статического статического метода, тело класса и глобальная область. Добавление к этому модификаторов доступа (публичный/частный/защищенный/внутренний – 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: }
При объявлении функции внутри неименованного пакета она размещается в глобальной области видимости и доступна всему коду. Тем не менее, все, что объявлено вне пакета, все еще находится в глобальной области видимости, но видимо только коду из того же файла.
[top]
Массивы
Массивы в AS3 очень похожи на массивы в PHP, но с одним отличием: в AS3 массив может иметь только численные индексы. Если вы хотите создать ассоциативный массив, то можете использовать класс Object. Если вы хотите создать хеш-карту, где ключами являются объекты (а не строки), то можно использовать класс Dictionary (Словарь). Создавайте массивы с помощью класса 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 (длина). Свойство length также можно использовать для уменьшения размера массива:
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 для задания конкретному элементу массива неопределенного значения: delete array[index]. Это не позволяет сократить длину массива. Можно использовать выражение for() для перебора элементов массива, используя его свойство length. Если вы хотите перебрать в цикле свойства объекта (опять же, это можно использовать для имитации ассоциативных массивов PHP), то можно использовать конструкцию for … each (которая работает аналогично такой же конструкции из РНР) или for … in (подробнее об этом в разделе о динамическом Actionscript).
[top]
Пространства имен
Если вы ищете в AS3 концепцию, эквивалентную пространствам имен в PHP, то вам следует почитать о пакетах в разделе «Классы», потому что пакеты в AS3 – это пространства имен в PHP.
В ActionScript пространства имен имеют другой смысл. Рассмотрим типичные случаи использования пространств имен, а затем приведем несколько примеров:
- Предотвращение конфликтов имен (можно создать несколько методов с одинаковыми именами в одном и том же классе, но каждый метод поместить в его собственное пространство имен).
- Придание особых настроек видимости переменным и методам во фреймворках или программах. Например, Flex использует пространство имен mx_internal; использование пространства имен вместо модификатора private или protected дает возможность использовать эти методы в любом пакете и классе из фреймворка Flex. В то же время, используя это пространство имен, разработчики фреймворка предупреждают, что эти методы или члены не предназначены для использования снаружи, поскольку они могут измениться.
- Управление доступом к классу на основе разрешений.
- Создание класса, который может переключаться между моделями поведения в зависимости от конкретного выбранного пространства имен.
Прежде чем углубляться в подробности, я должен заметить, что пространства имен используется внутри Flash Player для реализации модификаторов доступа public, protected, internal и private (публичный, защищенный, внутренний, приватный).
Определяйте пространства имен, используя такой синтаксис: namespace идентификатор = URI. Идентификатор – это то, что вы будете использовать при объявлении переменных и методов, а также для обозначения членов или методов при их использовании. URI – это обычно некий URL, который должен быть уникальным в рамках вашего приложения. Он не обязан реально существовать, в большинстве случаев вы будете использовать свое доменное имя. Например, я бы определил пространство имена так: namespace online = “http://flash-ripper.com /apps/online”.
Вы можете определить пространство имен в любом месте, где может быть определена переменная: на верхнем уровне описания пакета (будет доступно всей программе) или на уровне класса (будет доступно только в том же классе, в котором определено). На уровне функции можно использовать только пространства имен, которые были определены в другом месте (это может понадобиться вам для доступа к переменной, которая была определена в другом месте с использованием этого же пространства имен; чтобы сделать это, вы должны знать URI).
Можно объявить метод или переменную в данном пространстве имен, поместив идентификатор пространства имен перед объявлением переменной. Например: mynamespace var a: int = 1. При определении переменной или метода в пространстве имен нельзя использовать другие модификаторы доступа (например, private).
Для вызова переменной или метода, определенной в пространстве имен, используется оператор именования пространства «::». Предположим, вы определили метод myMethod() в пространстве имен online, в этом случает вы можете получить доступ к этому методу, используя следующий синтаксис: objectInstance.online::myMethod(). То же самое – с переменными. Иногда вам может понадобиться много переменных или методов из одного и того же пространства имен. В таком случае вы можете открыть пространство имен в этой области видимости и таким образом избавиться от оператора именования пространства «::». Это делается с помощью директивы use namespace имяпространства. Например:
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() в каждом из двух пространств имен. У меня есть приватная переменная _mode для хранения конкретного пространства имен, используемого в зависимости от состояния подключения к Сети. Вызывающая программа получает доступ к используемому пространству имен с помощью геттера и использует это пространство для вызова метода save(). Опять же, вызывающая программа не знает ни всех этих внутренностей, ни этих пространств имен, ей все равно. Посмотрим код 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). Комбинируя это с местом размещения определения пространства имен, вы получаете больший контроль над видимостью пространств имен в программе.
[top]
Работа с XML
В PHP есть мощная поддержка XML с помощью встроенных функций и дополнительных расширений. В AS3 есть два класса, представляющих собой XML изначально: XML и XMLList. В AS3 реализация класса XML основана на W3C DOM (есть методы children(), appendChild(), parent(), insertChildBefore() и т. д.). При работе с XML хорошо будет знать о том, как использовать E4X (ECMAScript-Для-XML), расширение языка ECMA-262 в AS3. Класс XML представляет XML-документ. Каждый узел документа завернут в XMLList, даже если он имеет только один дочерний узел.
Можно создать XML-объект любым из следующих способов:
- Создать XML с помощью литерала – буквального определения.
- Создать экземпляр класса XML, а затем импортировать XML из внешнего файла.
- Создать экземпляр XML и использовать точечную нотацию для добавления или изменения структуры:
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, можно легко найти узлы путем создания условий, основанных на именах узлов или значениях атрибутов. Можно использовать оператор доступа к потомкам “..” для получения всех узлов с заданным именем (например, для получения всех узлов program, можно написать: 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);
[top]
Динамический ActionScript
Помните определение AS3? Я говорил, что AS3 является динамическим скриптовым языком. Давайте копать немного глубже в эту сторону. Динамический – означает, что объект может быть изменен во время выполнения путем добавления или удаления его методов и/или членов. Можно добавлять новые методы самого класса (и любой созданный из этого класса объект будет иметь те же методы). Можно даже создавать новые классы с нуля (с помощью свойства prototype). В AS3 есть встроенные динамические объекты, такие как Object, а во Flex есть еще один пример, ObjectProxy.
Если вам интересно, почему в AS3 есть эти возможности, то ответ прост: в ранних версиях ActionScript не было такого продвинутого ООП, которое есть у него сегодня. Надо сказать, что, исходя из моего опыта, немногие разработчики используют динамические возможности AS3. Для этого есть несколько причин. Во-первых, время доступа к динамическим членам больше, чем к фиксированным. Во-вторых, в итоге получается код, более уязвимый к ошибкам (например, при компиляции эти ошибки не обнаруживаются).
Вы не ограничены встроенными классами и можете создавать динамические объекты с помощью модификатора dynamic при определении класса:
1: dynamic public MyDynamicObject {
2:
3: }
Теперь при использовании этого класса можно добавлять членов во время выполнения (помните, что все динамические переменные экземпляра не имеют типа и являются публичными):
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: }
[top]
Flex асинхронен
До сих пор мы рассматривали возможности Flex, из которых многие сходны с аналогичными в PHP. А вот асинхронная природа Flex является чем-то отличным от всего, что есть в РНР. Важно понять это, перестать с этим бороться и просто отдаться течению.
Что это значит – Flex является асинхронным? Предположим, вы создаете Flex-приложение, и после его загрузки в браузер, пользователь может выбрать картинки для загрузки с других сайтов. Можно использовать класс URLLoader для решения этой задачи. При выполнении метода load() в следующей строке кода у вас еще не будет загруженных данных. Выполнение кода не останавливается после вызова load(), чтобы дождаться появления загруженных данных. Вместо этого код продолжает выполняться. Как программист, вы работаете с этой асинхронной природой, используя встроенную в AS3 систему событий. Если вы знакомы с программированием AJAX, то знайте, что это аналогично вызовам AJAX: вы предоставляете функцию обратного вызова (callback), и когда данные поступают, эта функция вызывается, а в ней вы можете получить доступ к уже загруженным данным.
Возвращаясь к примеру с 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 является клиентской технологией. Если бы все вызовы были синхронными, то интерфейс пользователя просто зависал бы каждый раз при загрузке данных. А пользователи не любят зависающие приложения.
Можете отменять некоторые события и даже изменить их поведение по умолчанию. Даю вам возможность самостоятельно изучить эти детали, если вам это нужно; а теперь у вас должно быть достаточно четкое представление о том, что такое события и слушатели событий.
[top]
Привязка данных, тэги метаданных и отражения
Binding, байндинг, или привязка данных – это еще одна особенность Флекса, облегчающая жизнь разработчика, а заодно она сокращает количество строк кода. Привязка данных – это элегантный способ связать представление данных с их моделью так, чтобы представление автоматически обновлялось при изменении модели.
Так как Flex используется для создания пользовательских интерфейсов, то Flex-компоненты, как правило, в результате отображают большое количество данных. При изменении этих данных, даже в режиме реального времени, обычно требуется показать новые данные, а не старые. Привязка данных позволяет очень легко этого добиться. Байндинг связывает свойство объекта (так называемый «источник») со свойством другого объекта (называемого «назначением») и поэтому, когда изменяется источник, то назначение также автоматически обновляется.
Во 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>
Метаданные Bindable для переменной labelValue помечают ее как источник для привязки данных. Затем я использую фигурные скобки “{}” в атрибуте метки text, чтобы отметить это свойство как пункт назначения в привязке данных. После установки байндинга текст будет изменяться каждый раз при изменении переменной 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 добавляет во время компиляции склеивающий код (помните – привязка данных не является возможностью самого Flash Player или AS3), и красота в том то, что вам не нужно писать этот код самостоятельно.
Хотя привязка данных предлагает простой способ связать модель данных с отображением, возможно падение производительности, если у вас есть много привязок к переменным, обновляющимся десятки или сотни раз в секунду. Для таких переменных нет необходимости обновлять интерфейс пользователя так часто, потому что есть предел частоты кадров, введенный в самом браузере (где-то около 50 кадров в секунду). Как результат – нет смысла в попытках отобразить сотни изменений в секунду в режиме реального времени.
Еще один момент, о котором нужно помнить: не все объекты могут участвовать в привязке. Например, объект (Object) и массив (Array) не могут быть привязаны, для их привязки нужно использовать классы ObjectProxie и ArrayCollection. Если при создании класса модели данных вы хотите, чтобы всех члены данного класса были привязываемыми, то можно поместить метаданные 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-тэгов. Это как раз случай с метаданными события Event. Например: предположим, что я пишу класс, генерирующий события при загрузке. Я могу использовать это тега метаданных Event для объявления типа события и его названия. Поступив таким образом, я могу затем использовать свойство movieLoadedEvent MXML-тэга MovieLoader для регистрации слушателя этого события. Посмотрим код класса и то, как можно использовать этот класс в 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 именаМетаТэгов, то вы можете добавить свои собственные тэги, а компилятор вставит их в готовый байт-код. Затем вы можете использовать эти тэги во время выполнения. Например, в этой статье можно прочесть о том, как использовать свои теги метаданных для создания возможности сохранять модель данных AIR-приложений (подробнее об Adobe AIR немного позже).
И это подводит меня к последней теме этого раздела: отражение. При использовании своих собственных метаданных вы должны полагаться на AS3 Reflection API.
В PHP есть полное объектно-ориентированное API отражения: Reflection, ReflectionFunction, ReflectionParameter, ReflectionMethod и так далее. Вот пример использования класса Reflection на простом PHP-классе:
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 class\n";
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, которые можно использовать для отражения: describeType(), getDefintionByName() и 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>
[top]
Где мои данные? Дайте их сюда!
Как PHP-разработчик, вы имеете прямой доступ к данным, их анализу и отображения на экране. Подключение к базе данных MySQL является одной из первых вещей, которой учится PHP- разработчик. На самом деле, я сомневаюсь, что вы сумели прочитать всю статью до этой точки, не заглянув в этот раздел .
Что насчет Flex? Я должен разочаровать вас, потому что у вас нет прямого доступа к данным, хранящимся в БД. Но хорошо в этом то, что вы можете продолжать писать PHP-файлы для чтения и записи данных в базу, даже при написании приложений на Flex . Почему же нет прямого способа чтения данных из базы? Из-за старой поговорки “Никогда не верьте клиенту!” Предположим, что клиент – это Flex-компонент, который умеет подключаться к серверу MySQL. Как можно сохранить данные пользователя так, чтобы их не было легко украсть и взломать базу данных? Задать разные имена и пароли для каждого пользователя и предоставить им эту информацию? Это лишь одна из причин того, чтобы не давать клиенту технологий подключения непосредственно к серверу баз данных без посредничества серверов приложений.
В основном, во Flex-приложениях для управления базами данных вы полагаетесь на серверный скрипт. Flex предлагает способ вызова страниц с сервера и получения ответа. Есть три разных способа подключения к серверному источнику данных: сервисы в стиле REST, веб-сервисы и Remoting (или RPC).
Для использования сервисов типа REST подходит класс HTTPService. Вы можете отправить переменные методом POST в запросе, а ответом может быть XML, JSON (есть сторонние библиотеки для разбора JSON) или другие форматы.
Если у вас есть веб-сервисы на сервере (SOAP/WSDL), можно использовать класс WebService.
Но самый интересный метод – это удаленный доступ, или Remoting с помощью класса RemoteObject. Есть три причины считать этот метод самым крутым. Во-первых, с помощью ремоутинга вы можете использовать любой серверный PHP-класс, вызывая его методы. В основном, на стороне Flex вы используете экземпляр RemoteObject, как будто это удаленный класс PHP. Во-вторых, можно сопоставить модель данных со стороны PHP модели данных на стороне ActionScript, и преобразование происходит автоматически. Это чрезвычайно важно, потому что при использовании типизированных объектов вы получаете преимущества проверки ошибок во время компиляции и завершенный код. Это означает, что код будет легче читать, и он более устойчив к ошибкам. И, в-третьих, формат сообщений для этого метода, AMF3 (Action Message Format) представляет собой бинарный формат, он намного компактнее и поэтому передается быстрее по сравнению с SOAP/XML/JSON, это особенно важно для больших объемов данных. Сам формат открыт, любой желающий может прочесть официальную документацию и использовать его в своих программах.
AMF3 быстрее, потому что он кодирует данные. Например, если одна и та же строка повторяется в наборе данных, то она кодируется лишь один раз, а все остальные ее вхождения являются ссылками. Если число занимает меньше, чем четыре бита, то используется только минимальное количество нужных для ее передачи байтов.
Джеймс Уорд (James Ward) из Adobe создал хороший тест, для демонстрации различий между Remoting и другими методами.
Remoting изначально поддерживается во Flex, однако на стороне сервера ситуация несколько другая. PHP изначально не поддерживает Remoting и AMF3.Поэтому на сервере нужна библиотека для удаленного доступа с PHP на сервере. Есть четыре доступных библиотеки, все они бесплатны, и я написал руководство по использованию каждый из них: Zend AMF, PHPAMF, WebORB for PHP и SabreAMF. А здесь можно увидеть их сравнение друг с другом.
Так как «родные» типы данных конвертируются автоматически (типы данных PHP – в типы AS3 и наоборот), то вы должны обратить внимание на то, как типы одного языка преобразуются в типы другого. Вот пример соответствия типов данных в библиотеке AMFPHP.
[top]
Аутентификация пользователя во Flex-PHP проектах
Так как же происходит аутентификация пользователя в проектах Flex плюс PHP? Ответ очень прост: как и для любого PHP-сайта, используйте сессии и проверку имени пользователя и пароля.
В основном, при вызове из Flex, идентификатор сессии добавляется автоматически. Таким образом, если пользователь был аутентифицирован ранее, то будет использоваться эта же сессия (т.е. текущая сессия).
Подробнее об этой теме читайте здесь.
[top]
Работа с проектами Flex и PHP
К счастью, и PHP, и Flex являются зрелыми технологиями, так что у вас есть выбор из массы инструментов. Я расскажу о некоторых из них в этом разделе.
[top]
Flex SDK и текстовые редакторы
Первый вариант, который можно рассмотреть, заключается в использовании бесплатного Flex SDK с открытым кодом, особенно если вы любите работу из командной строки и текстовые редакторы типа vi . Вы можете писать код в вашем любимом текстовом редакторе и использовать средства командной строки для компиляции и отладки приложений.
[top]
Flex Builder / Flash Builder и Eclipse PDT / Zend Studio
Я предпочитаю использовать современные IDE. Для Flex и PHP-проектов лучшей комбинацией будет Flex Builder или Flash Builder 4 и Zend Studio. Flex Builder – это название Flex IDE от Adobe до четвертой версии, а в четвертой он был переименован во Flash Builder 4. Он основан на Eclipse IDE и доступен для Windows и Mac OS, есть его версия в виде плагина, а также автономная версия. Например, если у вас есть Zend Studio, то вы можете попробовать использовать Flash Builder Plug-In и установить этот плагин поверх Zend Studio. Вы можете использовать пробную версию Flex Builder 3 60 дней, а Flash Builder 4 находится сейчас в предрелизной бета-версии (зима 2010). Если Вы преподаватель или студент, то вы можете получить лицензию бесплатно.
Если вы предпочитаете работать с Eclipse PDT, то вы можете использовать тот же подход: установить плагинную версию Flash Builder 4 или наоборот, установить PDT поверх автономной версии Flash Builder.
Flash Builder 4 предлагает набор мастеров для работы с PHP и Flex: он может проанализировать PHP-код и сгенерировать по нему AS3 и Flex-код (здесь учебник по этому вопросу). Можно использовать его для отладки, замеров производительности (профайлинга), компиляции и запуска приложений (веб или AIR). Вы также можете экспортировать релизную версию приложения, есть также поддержка рефакторинга, а также режим дизайна интерфейса и редактор состояний.
Он также интегрируется с Flash Catalyst, так что вы можете создавать интерфейс пользователя во Flash Catalyst, а затем открыть сгенерированный проект во Flash Builder 4 и продолжить добавление бизнес-логики (смотрите этот скринкаст, чтобы увидеть, как можно создать вертикальную полосу прокрутки c помощью Adobe Illustrator, Flash Catalyst и Flash Builder 4).
Есть и другие IDE (это коммерческие продукты) для Flex: IntelliJ IDEA и FDT (основан на Eclipse).
[top]
Отладка Flex-приложений
Можно отлаживать Flex-код с помощью отладчика Flex SDK или отладчика Flash Builder 4 (или Flex Builder 3). Если вы выбрали комбинированную установку Flash Builder 4 и Zend Studio, то можно легко отлаживать код PHP и код Flex из одного и того же проекта. Вы делаете вызов из Flex в PHP, а затем можете войти в отладчик PHP, а затем, когда ответ пришел из PHP во Flex, окажетесь в отладчике Flex. Здесь и здесь есть некоторые видео на эту тему, а здесь есть урок по отладке в Zend Studio и Flex Builder.
Один из моих первых подходов при отладке ошибок в PHP – это использование комбинации вызовов die() и var_dump (), чтобы увидеть, что происходит. В AS3 можно использовать trace() для вывода значений переменных на консоль. Отлично, что при компиляции приложений для релиза все вызовы trace() удаляются. Это ненавязчивый способ вывода информации; вы также можете использовать класс Alert для отображения сообщений во всплывающем окне (это больше похоже на JavaScript до появления FireBug).
Ключевой момент, который нужно помнить: теперь у вас есть клиент, который отделен от сервера, а проблемы могут быть как на стороне клиента, так и на сервере, или же на уровне сети.
Вы можете узнать больше об отладке Flex и PHP проектов здесь.
[top]
Что такое Adobe AIR
Adobe AIR – это среда выполнения RIA для рабочего стола, которая может выполнять настольные приложения на Windows, Mac и Linux. С помощью AIR вы можете создавать одно приложение, которое может работать на любой из этих операционных систем. Примеры AIR-приложений: Tour de Flex, TweetDeck, Times Reader, Dojo Toolbox, и Sideline from Yahoo!.
Вы можете представить себе Adobe AIR как Flash Player для рабочего стола. Вместе с этим, Adobe AIR – это больше, чем просто модифицированный Flash Player.
Внутри этой среды выполнения есть HTML-движок (WebKit, тот же движок используют Safari и Google Chrome) и модифицированный движок Flash Player. Оба эти движка дают набор программных интерфейсов, предоставляющих доступ к машине, на которой запускается AIR-приложение. Есть API для записи и чтения файлов с диска, для обнаружения сетевых подключений, для выявления количества подключенных мониторов и разрешения экрана, для автоматического обновления приложений, для уведомлений рабочего стола, для работы с локальными базами данных и зашифрованным локальным хранилищем, для перетаскивания объектов мышкой между приложением и десктопом и многое другое.
Как веб-разработчик, вы можете выбрать любую комбинацию из следующих технологий: Flex, ActionScript 3, или HTML/CSS/JavaScript. Да, это так, вы можете создать AIR-приложение, используя только HTML, JavaScript и CSS! На самом деле, приложения Dojo Toolbox и Sideline от Yahoo! созданы с помощью HTML/CSS/JS.
Так что с AIR вы можете использовать свои существующие навыки для создания настольных приложений. Но почему вам может понадобиться создавать веб-приложение, работающее как настольное? На самом деле, для этого есть много причин:
- Вы хотите иметь возможность использовать приложение или его части, когда у вас нет подключения к Интернету.
- Вы хотите избавиться от хрома браузера и полностью контролировать внешний вид вашего приложения.
- Вы хотите иметь возможность интегрировать ваше приложение с другими приложениями на компьютере пользователя (например, для перетаскивания файлов из AIR-приложения на рабочий стол и наоборот).
- Вы хотите сохранять файлы на компьютере пользователя.
- Вы хотите создать систему оповещений и хотите запускать приложение свернутым в системный трей (например, аська может сообщать вам о новом сообщении даже когда она свернута в трей и не имеет фокуса).
- Масса других причин, вызванных возможностью быстрой реализации ваших собственных инновационных идей для десктопа.
Для разработки AIR-приложений можно использовать бесплатный AIR SDK (там есть инструменты командной строки для создания, тестирования и отладки приложений), а также вы можете использовать Aptana Studio для создания AIR-приложений на HTML/JS/CSS, а можно делать AIR во Flash Builder 4 или Flex Builder 3.
Наконец, любое Flex-приложение, которое было создано для браузера, может быть конвертировано в AIR-приложение в мгновение ока. Конечно, если вы на этом остановитесь и не станете использовать возможности AIR, то это не имеет смысла, так как вы не предоставили пользователю приложения никакой дополнительной ценности в такой настольной версии, так что стоит подумать об этом.
[top]
Что будет с Flash дальше?
В начале 2010 года выйдет Flex 4. Adobe разработала новый инструмент Flash Catlyst (Катализатор Флэша, он еще в бета-версии), который можно использовать для преобразования созданного в Photoshop или Illustrator статического дизайна в функциональные интерфейсы пользователя Flex-приложений. Представьте себе инструмент, на входе принимающий файл в формате Photoshop или Illustrator, а на выходе дающий HTML/CSS/JavaScript-код, при этом сохраняя дизайн и замысел исходных файлов. Это то, что делает Flash Catalyst, только он выводит код для Flex 4, а не HTML.
В то же время, мы cконцентрированы на том, чтобы платформа Flash была доступна на любых экранах: от компьютеров до мобильных устройств, от приставок для видеоигр до телевизоров. Теперь у нас есть Flash Lite 3, доступный на мобильных телефонах Nokia, Sony Ericsson, HTC, Android и Palm. В следующем году мы выпустим мобильную версию Flash Player 10.1 с поддержкой Multi-Touch, акселерометра и других полезных вещей. Кроме того, вполне возможно, что в следующем году мы увидим первые телевизоры с поддержкой Flash. Как круто будет иметь в телевизоре интерфейс пользователя со всеми преимуществами Flash Player, или смотреть видео высокого разрешения из Сети (Flash поддерживает стандарт Н.264). Некоторые аналитики считают, что в ближайшем будущем подключенных к Интернету мобильных телефонов станет больше, чем компьютеров, и многие люди будут использовать свои мобильные в качестве основного средства доступа к Интернету, поскольку у них не будет компьютера.
Что это означает для веб-разработчика? Это означает, что вы можете расширить свою сферу компетенции и сферу ваших бизнес-предложений – от веб-сайтов до RIA на рабочем столе (с помощью Adobe AIR), и от компьютеров до мобильных телефонов и других устройств с экранами. Конечно, для того, чтобы сделать это, вам нужно освежить в памяти некоторые из ваших навыков, но этот уровень сложности даже близко не подходит к уровню освоения специальностей типа C или C++ для данной платформы.
[top]
Куда теперь идти и что теперь делать
Надеюсь, вы нашли ответы на некоторые свои вопросы. Если вы серьезно намерены войти в мир Flex, то вот некоторые ресурсы:
Tour de Flex
Я вижу Турдефлекс как Web 2.0 или РИА-версию любимого php_manual.chm. Вы можете установить его здесь. Он дает примеры использования всех Flex-компонентов, там можно увидеть, как они выглядят, и используемый для этого код. Там также есть легкий доступ к документации по Flex. Само приложение создано с помощью Flex и Adobe AIR.
Книги
Есть много книг о Flex и ActionScript 3, а мои личные фавориты, и те, я обычно рекомендую, таковы:
- First steps in Flex, от Брюса Эккеля (Bruce Eckel) и Джеймса Уорда (James Ward – технический евангелист в Adobe); эта книга дает обзор возможностей Flex для разработки веб- и настольных приложений, и вы можете прочитать ее за одни выходные.
- Основы ActionScript 3.0 на русском языке от Колина Мука (Colin Moock); это толстая кни