Передача настраиваемых типизированных объектов в качестве аргументов при вызове метода службы PHP

Мы используем zendamf в качестве шлюза удаленного взаимодействия между гибким клиентом и сервером PHP. Сопоставление типов на стороне сервера с типами на стороне клиента, похоже, не влияет на объекты, передаваемые в качестве параметров метода службы. Все объекты с настраиваемыми типами принимаются как экземпляры stdClass. Есть ли способ заставить это? Или нам здесь чего-то не хватает?

Есть предположения?

Спасибо!


person Bert Vandamme    schedule 21.10.2011    source источник
comment
В ColdFusion вы должны быть уверены, что свойства в определении класса отображаются в том же порядке и с одинаковой чувствительностью к регистру как на стороне Flex, так и на стороне CF. Также убедитесь, что вы определили метаданные RemoteAlias ​​в классе Flex и атрибут псевдонима в CF CFC (класс AKA). Я предполагаю, что вы должны делать аналогичные вещи в PHP. Ты? Вы можете показать код?   -  person JeffryHouser    schedule 21.10.2011


Ответы (1)


Немного старше этот вопрос, но еще не ответил. Так что позволь мне попробовать. ;)

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