我们使用 zendamf 作为 flex 客户端和 PHP 服务器之间的远程网关。将服务器端类型映射到客户端类型似乎对作为服务方法参数传递的对象没有任何影响。所有具有自定义类型的对象都作为 stdClass 实例接收。有没有办法强制这样做?或者我们在这里错过了什么?
有什么想法吗?
谢谢!
我们使用 zendamf 作为 flex 客户端和 PHP 服务器之间的远程网关。将服务器端类型映射到客户端类型似乎对作为服务方法参数传递的对象没有任何影响。所有具有自定义类型的对象都作为 stdClass 实例接收。有没有办法强制这样做?或者我们在这里错过了什么?
有什么想法吗?
谢谢!
这个问题有点老了,但还没有回答。所以让我试试。;)
首先@www.Flextras.com:你是对的。在 PHP 中,还需要做一些类映射。
因此,对于所有对如何使用 Zend 框架定义类映射感兴趣的人,请查看以下简短但(在我看来)详细的介绍。如果您了解所有这些,请跳过介绍并继续阅读“关于 Zend 框架中的客户端到服务器映射和 stdClass”
正如 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 将无法转换为强类型对象。相反,您将获得泛型Object
类的实例。如果发生这种情况,您应该检查是否存在以下一种或多种情况。
[RemoteClass]
元数据标签。[RemoteClass(alias="")]
) 指定了远程类,请检查您是否输入了错误。public var ...
或 getter/setter 对)[Transient]
?(这将排除如此标记的属性被序列化/反序列化)[RemoteClass]
(ActionScript 类名必须与Flex 应用程序的标签中定义的完全相同)我还遇到了将强类型参数传递给服务器端的服务类方法的问题,导致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 框架的命名约定,但不幸的是,这可能需要数小时的重构(这在 PHP 中并不容易处理)并且可能需要数天的测试和调试你的整个代码库。
为了取得平衡,您可以对所需的框架类进行猴子补丁。因此,您不会更改框架本身,但也不会重构您的代码库。有一些框架可以解决问题。我在这个问题的答案中找到了一些例子
另外在这里发现了这个问题: AMF typed objects from flex back to PHP 你应该检查它是否符合你的需要。
希望这对某人有帮助。告诉我我是否忘记了什么(例如在清单中!)