Немного старше этот вопрос, но еще не ответил. Так что позволь мне попробовать. ;)
First @ www.Flextras.com: Вы правы. В PHP также необходимо сделать некоторые вещи для сопоставления классов.
Итак, для всех, кто интересуется тем, как определять сопоставление классов с помощью Zend Framework, обратите внимание на следующее короткое, но (на мой взгляд) подробное введение. Если вы все это знаете, пропустите введение и перейдите к разделу «О сопоставлении клиент-сервер и stdClass в Zend Framework».
Способы сопоставления классов в PHP с использованием Zend Framework
Как описано в документации Zend Framework Zend_Amf_Server, у вас есть 3 варианта предоставления сопоставления классов. Вы можете найти полную документацию здесь (где-то в середине страницы под «Типизированные объекты»).
Первый вариант
// Use the setClassMap() method of Zend_Amf_Server
require_once '<PathToZendFramework>/Zend/Amf/Server.php';
$server = new Zend_Amf_Server();
$server->setClassMap('MyActionScriptClassName', 'MyPHPClassName');
// the typical package notation for ActionScript class names is also allowed here
$server->setClassMap('com.company.MyActionScriptClassName', 'MyPHPClassName');
Это наиболее гибкий вариант, поскольку вы можете явно указать сопоставления классов для обоих направлений: от клиента к серверу и от сервера к клиенту. В отличие от гибкости здесь можно сделать больше ошибок. Ниже вы найдете контрольный список, который следует учитывать при использовании сопоставления классов.
Второй вариант
// Define a special named public property on each class used for
// serialization/deserialization via AMF
public class MyPHPClassName
{
public $_explicitType = 'MyActionScriptClassName';
/* your class definition here */
}
Таким образом сопоставление классов становится немного более динамичным, поскольку Zend_Amf_Server будет автоматически искать свойство $_explicitType
. Таким образом, вам не нужно явно определять сопоставление классов, как в первом варианте. К сожалению, используя $_explicitType
, вы не можете определить имя класса PHP для сопоставления (это «немного более динамично»). Ниже вы найдете подробное описание проблемы, которая здесь возникает.
Третий вариант
// Define a special named public method on each class used for
// serialization/deserialization via AMF
public class MyPHPClassName
{
public function getASClassName()
{
return 'MyActionScriptClassName';
}
/* your class definition here */
}
Используя этот последний вариант, вы получите максимальную динамику от сопоставления классов. Вы можете просто вернуть строковый литерал, как в моем примере, но это будет то же самое, что и при использовании параметра $_explicitType
. Преимущество методического подхода состоит в том, что классы позволяют динамически генерировать имя класса ActionScript. Таким образом, вы можете определить getASClassName()
в самом верхнем классе иерархии, от которого наследуются все ваши классы AMF. Недостаток здесь такой же, как и у второго варианта. Вы не можете определить имя класса PHP, которому класс сопоставляется.
Контрольный список сопоставления классов для Flex и Zend Framework
Если вы сделали что-то неправильно при указании сопоставления классов, Flex не сможет преобразовать в строго типизированные объекты. Вместо этого вы получите экземпляр универсального класса Object
. Если это произойдет, вы должны проверить, верно ли одно или несколько из следующих событий.
На стороне Flex
- У вашего класса должен быть тег метаданных
[RemoteClass]
.
- Если вы указали удаленный класс с псевдонимом (
[RemoteClass(alias="")]
), проверьте, не допустили ли вы опечатку.
- Определяет ли ваш класс (включая все классы, от которых он наследуется) все общедоступные свойства, определенные в эквиваленте на стороне сервера? (может быть либо
public var ...
, либо парой геттер / сеттер)
- Вы определили общедоступные свойства как readwrite?
- Вы отметили свойства, которые не следует использовать для передачи, с помощью тега метаданных
[Transient]
? (Это исключит сериализацию / десериализацию отмеченного таким образом свойства)
На стороне Zend Framework
- Вы использовали один из трех вариантов сопоставления классов?
- Если вы использовали первый вариант, то не ошиблись ли вы в имени класса ActionScript или PHP? (Имя класса ActionScript должно быть таким же, как определено в теге
[RemoteClass]
в вашем приложении Flex)
О сопоставлении клиент-сервер и stdClass в Zend Framework
Я также столкнулся с проблемой, когда строго типизированные аргументы передавались методам класса службы на стороне сервера, что приводило к stdClass
. Я часто пытался выяснить, почему это происходит, но никогда не находил времени, чтобы по-настоящему найти причину. Вчера, после дополнительной попытки сделать сопоставление классов как можно более динамичным / универсальным в одном из моих проектов и после нескольких часов исследований, я обнаружил, что Zend_Amf_Server будет делать при получении запроса AMF. (Кстати: я никогда не находил причину, если бы я не реализовал строгие соглашения об именах классов в моем PHP-коде).
Когда поступает запрос AMF и Zend_Amf_Server начинает его синтаксический анализ, он считывает некоторый псевдоним удаленного класса из запроса и пытается загрузить этот класс автоматически. Это то, что мы хотим, чтобы Zend_Amf_Server делал, верно !? Но сервер AMF поддерживает только автоматизмы для обработки имен классов, таких как MyClassName
, или соответствия соглашениям об именах фреймворка, например, My_Class_Name
. Вы не можете автоматически сопоставить классы с псевдонимом удаленного класса, например com.company.SomeAmfClass
. Zend ожидает, что вы указали пакет (который представляет собой обычный путь к каталогу), и преобразует все точки в символы подчеркивания перед попыткой загрузить класс. Класс, который будет делать это, - Zend_Amf_Parse_TypeLoader
. Сервер AMF вызовет на нем статический метод loadType()
.
Вот реализация этого метода (скопирована прямо из Zend Framework 1.11.7):
/**
* Load the mapped class type into a callback.
*
* @param string $className
* @return object|false
*/
public static function loadType($className)
{
$class = self::getMappedClassName($className);
if(!$class) {
$class = str_replace('.', '_', $className);
}
if (!class_exists($class)) {
return "stdClass";
}
return $class;
}
Сначала я попытался определить класс, реализующий Zend_Loader_Autoloader_Interface
, и поместил его в стек автозагрузчика Zend_Loader_Autoloader
синглтона. Но проблема заключалась в том, что Zend_Amf_Parse_TypeLoader::loadType()
изменяет имя класса перед автозагрузкой - что происходит при вызове class_exists()
.
Итак, что вы могли бы сделать, так это изменить этот метод непосредственно в структуре, чтобы дополнительно обрабатывать имена классов ActionScript, например com.company.SomeAmfClass
. Но это должен быть самый последний вариант, потому что изменение кода фреймворка - плохая практика!
Другое решение - и почти самое чистое - заключалось бы в реорганизации и переименовании всех ваших классов, чтобы они соответствовали соглашениям об именах Zend Framework, но, к сожалению, это может занять часы рефакторинга (что на самом деле не так просто в PHP) и, возможно, дни тестирования и отладка всей вашей кодовой базы.
Чтобы найти баланс, вы можете исправить требуемые классы фреймворка. Таким образом, вы не будете менять сам фреймворк, но и не реорганизуете свою кодовую базу. Есть несколько фреймворков, которые помогут. Я нашел несколько примеров в ответах на этот вопрос
Дополнительно нашел здесь этот вопрос: Типизированные объекты AMF из гибкого обратно в PHP Вы должны проверить, соответствует ли он вашим потребностям.
Надеюсь, это будет кому-то полезно. Скажите, если я что-то забыл (например, в контрольном списке!)
person
eddipedia
schedule
29.08.2012