我们使用zendamf作为flex客户端和PHP服务器之间的远程网关。将服务器端类型映射到客户端类型似乎对作为服务方法参数传递的对象没有任何影响。所有具有自定义类型的对象都作为stdClass实例接收。有办法强迫这个吗?还是我们遗漏了什么?
任何想法吗?
谢谢!
这个问题有点老了,但还没有答案。我来试试。;)
第一@www.Flextras.com:你说得对。在PHP中,做一些类映射也是必要的。
因此,对于所有对如何通过使用Zend框架定义类映射感兴趣的人,请查看以下简短但(在我看来)详细的介绍。如果你知道所有这些,那么跳过介绍,继续阅读"关于客户端到服务器映射和Zend框架中的stdClass">
使用Zend框架实现PHP类映射的方法
正如Zend框架的Zend_Amf_Server的文档所描述的,你有3个选项来提供类映射。你可以在这里找到完整的文档(在页面中间的"类型化对象"下)。
<<h3>第一选项/h3>// 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类名。因此,您可以在所有AMF类继承的层次结构中最顶层的类上定义getASClassName()
。这里的缺点与第二个选项相同。您不能定义类映射到的PHP类名。
Flex和Zend框架的类映射清单
如果在指定类映射时出错,Flex将无法转换为强类型对象。相反,您将获得一个通用Object
类的实例。如果发生这种情况,您应该检查是否有以下一种或多种情况。
Flex侧
- 你的类必须有一个
[RemoteClass]
元数据标签。 - 如果您使用别名(
[RemoteClass(alias="")]
)指定远程类,则检查您是否犯了输入错误。 你的类(包括它继承的所有类)定义了在服务器端等效定义的所有公共属性吗?(可以是
public var ...
或getter/setter对)你把公共属性定义为读写了吗?你是否用[Transient]
元数据标签标记了不用于传输的属性?(这将排除so-marked属性被序列化/反序列化)在Zend Framework端
- 您是否使用了三个类映射选项中的一个?
- 如果你使用了第一个选项,那么你是否错误地输入了ActionScript或PHP类名?(ActionScript类名必须与在Flex应用程序的
[RemoteClass]
标签中定义的完全相同)
关于Zend Framework中client-to-server映射和stdClass
我还遇到了强类型参数传递给服务器端服务类方法导致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中并不容易处理),可能需要几天的测试和调试你的整个代码库。
为了达到平衡,您可以对所需的框架类进行猴式补丁。因此,您不必更改框架本身,但不必重构代码库。有一些框架可以做到这一点。我在这个问题的答案中找到了一些例子另外在这里发现了这个问题:从flex到PHP的AMF类型对象你应该检查一下它是否符合你的需要。
希望这将对某人有所帮助。如果我忘记了什么,告诉我(比如在清单上!)