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. Теперь посмотрим содержание, а затем – погрузимся в материал!

  1. Что такое Flex?
    1. Flex: два языка и один фреймворк, чтобы связать их
    2. Почему вам нужно знать про Flex
    3. От тонкого клиента к умному и богатому клиенту
  2. Введение в язык MXML
    1. Смешивание MXML  ActionScript 3
    2. CSS-стили
    3. Изменение MXML-кода во время выполнения
  3. Введение в язык ActionScript 3
    1. Разделение выражений
    2. Типы данных, переменные, константы
    3. Функции и анонимные функции (замыкания)
    4. OOП: классы и интерфейсы
    5. Область видимости переменной
    6. Массивы
    7. Пространства имен
    8. Работа с XML
    9. Динамический ActionScript
  4. Flex асинхронен
  5. Связывание данных, метаданные и отражение
  6. Где мои данные, давайте их сюда!
  7. Аутентификация пользователя во Flex- и PHP-проектах
  8. Работа над проектами Flex и PHP
    1. Flex SDK
    2. Flex Builder / Flash Builder
    3. Отладка Flex-приложений
  9. Что такое Adobe AIR?
  10. Что будет с Flash дальше??
  11. Куда направиться после всего этого

Что такое 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.flex_php_0[top]

Flex: два языка и один фреймворк, чтобы их связать

Под крышей Flex на самом деле можно найти вот что:

  • Два языка: MXML и ActionScript 3. Flex предлагает два языка для разработки приложения. В следующих главах я углублюсь в каждый из них.
  • Богатая библиотека компонентов.
  • Компиляторы и отладчик.
  • Инструменты командной строки для компилирования и отладки приложения Flex.

Так как Flex является фреймворком с открытым исходным кодом, то я призываю вас сходить на домашнюю страницу этого проектаhttp://opensource.adobe.com/flex и скачать SDK. Вы можете увидеть исходный код всех компонентов библиотеки, может проверить открытую базу данных багов и фич (http://bugs.adobe.com/flex), и вы можете увидеть страницы вики со спецификациями.

Частично высокая продуктивность Flex обеспечивается большой библиотекой компонентов. Там есть все мыслимые UI-компоненты (поля ввода, панели, окна, слайдеры, датагриды, комбобоксы, аккордеоны, табуляторы…) Есть контейнеры для разметки и элементы форм. Ниже вы увидите скриншот с доступными компонентами Flex 3 (кликните, чтобы увеличить).

flex_php_1

И если этих компонентов вам недостаточно, то вы можете создать свои или расширить существующие, так как у вас есть доступ к исходным кодам.

[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>

Ниже показано, как выглядит приложение:

flex_php_2

Вы можете подумать, что в 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. Приложение теперь выглядит следующим образом:

flex_php_3

CSS-стили могут быть изменены во время выполнения программы (после того, как Flex-приложение загрузилось в браузер), и внешний вид приложения сразу изменится.

Во Flex 4 Adobe добавила новый язык, называемый MXML для графики –FXG, который добавляет графические примитивы, эффекты, маски и 2D-преобразования. Можно создавать класс скина (кожи) в MXML-файле,  используя эти новые теги, а затем назначить этот класс компоненту, который нужно обеспечить скином (кожей). Ниже показан скинованый список Flex 4. Слева показан список в состоянии по умолчанию, а в правой части – состояние при наведении мыши (hover). Можно увидеть приложение в действии здесь.

flex_php_4 flex_php_5

Блуждая по документации настройки вида 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 состояния работают так:

  1. Вы определяете некоторое количество состояний и задаете состояние по умолчанию;
  2. Вы можете указать, в каком состоянии должен появиться конкретный компонент;
  3. Вы можете указать отдельные значения для любого атрибута для каждого состояния, в котором появляется компонент.

Предположим, вы хотите создать компонент, реализующий функцию авторизации в приложении. Вы хотите использовать этот компонент для отображения формы логина, и когда пользователь вошел удачно, вы хотите показать кнопку выхода и имя пользователя. Вот как вы можете создать компонент 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 имеет: publicprivateprotectedstatic

    AS3 имеет те же модификаторы что и PHP плюс internal. Internal используется для того, чтобы сделать свойства доступными только изнутри того же пакета. Когда модификатор не указан, используется internal.

    Модификаторы для методов класса:

    • В PHP: publicprivateprotectedstaticfinal и abstract.
    • В AS3: publicprivateprotectedstaticfinalinternal и 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), то можно использовать конструкцию foreach (которая работает аналогично такой же конструкции из РНР) или forin (подробнее об этом в разделе о динамическом Actionscript).

    [top]

    Пространства имен

    Если вы ищете в AS3 концепцию, эквивалентную пространствам имен в PHP, то вам следует почитать о пакетах в разделе «Классы», потому что пакеты в AS3 – это пространства имен в PHP.

    В ActionScript пространства имен имеют другой смысл. Рассмотрим типичные случаи использования пространств имен, а затем приведем несколько примеров:

    1. Предотвращение конфликтов имен (можно создать несколько методов с одинаковыми именами в одном и том же классе, но каждый метод поместить в его собственное пространство имен).
    2. Придание особых настроек видимости переменным и методам во фреймворках или программах. Например, Flex использует пространство имен mx_internal; использование пространства имен вместо модификатора private или protected дает возможность использовать эти методы в любом пакете и классе из фреймворка Flex. В то же время, используя это пространство имен, разработчики фреймворка предупреждают, что эти методы или члены не предназначены для использования снаружи, поскольку они могут измениться.
    3. Управление доступом к классу на основе разрешений.
    4. Создание класса, который может переключаться между моделями поведения в зависимости от конкретного выбранного пространства имен.

    Прежде чем углубляться в подробности, я должен заметить, что пространства имен используется внутри Flash Player для реализации модификаторов доступа public, protected, internal и private (публичный, защищенный, внутренний, приватный).

    Определяйте пространства имен, используя такой синтаксис: namespace идентификатор = URI. Идентификатор – это то, что вы будете использовать при объявлении переменных и методов, а также для обозначения членов или методов при их использовании. URI – это обычно некий URL, который должен быть уникальным в рамках вашего приложения. Он не обязан реально существовать, в большинстве случаев вы будете использовать свое доменное имя. Например, я бы определил пространство имена так: namespace online = “http://flashripper.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-объект любым из следующих способов:

    1. Создать XML с помощью литерала – буквального определения.
    2. Создать экземпляр класса XML, а затем импортировать XML из внешнего файла.
    3. Создать экземпляр 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";

    Можно перебирать всех членов динамического класса, используя цикл foreachin. Вот как показать всех членов из предыдущего примера:

       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>

    С метаданными можно делать и другие интересные вещи. Если вы установили опцию компилятора keepas3-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).

    flex_php_10

    Для использования сервисов типа 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 быстрее, потому что он кодирует данные. Например, если одна и та же строка повторяется в наборе данных, то она кодируется лишь один раз, а все остальные ее вхождения являются ссылками. Если число занимает меньше, чем четыре бита, то используется только минимальное количество нужных для ее передачи байтов.

    flex_php_11

    Джеймс Уорд (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!.

    flex_php_12

    Вы можете представить себе Adobe AIR как Flash Player для рабочего стола. Вместе с этим, Adobe AIR – это больше, чем просто модифицированный Flash Player.

    Внутри этой среды выполнения есть HTML-движок (WebKit, тот же движок используют Safari и Google Chrome) и модифицированный движок Flash Player. Оба эти движка дают набор программных интерфейсов, предоставляющих доступ к машине, на которой запускается AIR-приложение. Есть API для записи и чтения файлов с диска, для обнаружения сетевых подключений, для выявления количества подключенных мониторов и разрешения экрана, для автоматического обновления приложений, для уведомлений рабочего стола, для работы с локальными базами данных и зашифрованным локальным хранилищем, для перетаскивания объектов мышкой между приложением и десктопом и многое другое.

    flex_php_6

    Как веб-разработчик, вы можете выбрать любую комбинацию из следующих технологий: 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_php_7

    Книги

    Есть много книг о Flex и ActionScript 3, а мои личные фавориты, и те, я обычно рекомендую, таковы:

    • Flex 4 in a Day – well this is not exactly a book. It is a 40-page documentation on Flex 4 that once read it, it should give you a good overview over Flex 4
    • First steps in Flex, от Брюса Эккеля (Bruce Eckel) и Джеймса Уорда (James Ward – технический евангелист в Adobe); эта книга дает обзор возможностей Flex для разработки веб- и настольных приложений, и вы можете прочитать ее за одни выходные.
    • Основы ActionScript 3.0 на русском языке от Колина Мука (Colin Moock); это толстая книга, и вы должны быть отличным читателем, чтобы прочесть ее за выходные. Хотя она не покрывает Flex, в ней можно узнать почти все об ActionScript 3.

    flex_php_8 flex_php_9

    Сайты

    Существуют сотни сайтов и блогов про Flex и ActionScript 3. Невозможно дать полный список, дам некоторые из моих любимых:

    • Adobe Developer Connection. Отличное место для чтения технических статей о Flash, Flex и AIR. Обновляется еженедельно. Существует раздел, посвященный Flex и PHP.
    • Adobe TV. На этом сайте есть тысячи кубометров видео с докладами конференций и видео-уроками.
    • Gotoandlearn.com. Отличная коллекция видео-уроков от другого евангелиста – Ли Бримелоу (Lee Brimelow).
    • Flex-документация. Имейте в виду, что вы можете скачать ZIP-файл этой документации. Здесь вы найдете ресурсы в различных форматах.
    • Группы Adobe. Это открытая платформа, где можно найти группы пользователей Adobe, в том числе Flex- и Flash- группы. Вот российская группа RAFPUG, а вот украинская UAFPUG, а вот – белорусская BAFPUG. Проверьте, нет ли группы пользователей в вашем регионе, обычно они организуют заседания ежемесячно и в разных городах. На сайте групп есть форумы, на них поддерживается локализация, так что там вы найдете содержимое не только на английском.
    • Мой блогролл. Посмотрите там; большинство из этих людей работают для Adobe, они пишут о Flash и Flex.
    • Посмотрите на этот список, который поддерживает автор статьи Михай Корлан. Там есть фреймворки, библиотеки и другие Flex-ресурсы.

    Теперь, я думаю, вы можете понять, почему, когда разработчик спрашивает меня, что такое Flex, я некоторое время просто тупо смотрю в пространство. За это время перед моими глазами проходят все тысячи слов, что я  написал здесь… так много можно сказать, и как уложить это все в одну строку!? Надеюсь, теперь я могу просто ответить “Флекс – это поразительно, чувак! Глянь вот эту статью  “.

    Если у вас есть комментарии, пожалуйста, найдите время, чтобы оставить их на этой странице или на странице английской версии статьи. Спасибо!

    [top]

    Leave a Reply

    Your email address will not be published. Required fields are marked *