|
30 | 30 | #include <ext/spl/spl_array.h>
|
31 | 31 | #include <Zend/zend_hash.h>
|
32 | 32 | #include <Zend/zend_interfaces.h>
|
| 33 | +#include <Zend/zend_string.h> |
33 | 34 |
|
34 | 35 | /* PHP array helpers */
|
35 | 36 | #include "src/contrib/php_array_api.h"
|
|
62 | 63 |
|
63 | 64 | #define PHONGO_ODM_FIELD_NAME "__pclass"
|
64 | 65 |
|
| 66 | +#define PHONGO_IS_CLASS_INSTANTIATABLE(ce) \ |
| 67 | + (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))) |
| 68 | + |
65 | 69 | PHP_MINIT_FUNCTION(bson)
|
66 | 70 | {
|
67 | 71 | (void)type; /* We don't care if we are loaded via dl() or extension= */
|
@@ -964,71 +968,63 @@ PHP_FUNCTION(fromPHP)
|
964 | 968 | }
|
965 | 969 | /* }}} */
|
966 | 970 |
|
| 971 | +static void apply_classname_to_state(const char *classname, int classname_len, php_phongo_bson_typemap_types *type, zend_class_entry **type_ce TSRMLS_DC) |
| 972 | +{ |
| 973 | + if (!strcasecmp(classname, "array")) { |
| 974 | + *type = PHONGO_TYPEMAP_NATIVE_ARRAY; |
| 975 | + *type_ce = NULL; |
| 976 | + } else if (!strcasecmp(classname, "stdclass") || !strcasecmp(classname, "object")) { |
| 977 | + *type = PHONGO_TYPEMAP_NATIVE_OBJECT; |
| 978 | + *type_ce = NULL; |
| 979 | + } else { |
| 980 | + zend_class_entry *found_ce = zend_fetch_class(classname, classname_len, ZEND_FETCH_CLASS_AUTO|ZEND_FETCH_CLASS_SILENT TSRMLS_CC); |
| 981 | + |
| 982 | + if (!found_ce) { |
| 983 | + phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Class %s does not exist", classname); |
| 984 | + } else if (!PHONGO_IS_CLASS_INSTANTIATABLE(found_ce)) { |
| 985 | + phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Class %s is not instantiatable", classname); |
| 986 | + } else if (!instanceof_function(found_ce, php_phongo_unserializable_ce TSRMLS_CC)) { |
| 987 | + phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Class %s does not implement %s\\Unserializable", classname, BSON_NAMESPACE); |
| 988 | + } else { |
| 989 | + *type = PHONGO_TYPEMAP_CLASS; |
| 990 | + *type_ce = found_ce; |
| 991 | + } |
| 992 | + } |
| 993 | +} |
| 994 | + |
967 | 995 | void php_phongo_bson_typemap_to_state(zval *typemap, php_phongo_bson_typemap *map TSRMLS_DC)
|
968 | 996 | {
|
969 | 997 | if (typemap) {
|
970 |
| - char *classname; |
971 |
| - int classname_len; |
972 |
| - zend_bool classname_free = 0; |
| 998 | + char *classname; |
| 999 | + int classname_len; |
| 1000 | + zend_bool classname_free = 0; |
973 | 1001 |
|
974 | 1002 | classname = php_array_fetchl_string(typemap, "array", sizeof("array")-1, &classname_len, &classname_free);
|
975 | 1003 | if (classname_len) {
|
976 |
| - if (!strcasecmp(classname, "array")) { |
977 |
| - map->array_type = PHONGO_TYPEMAP_NATIVE_ARRAY; |
978 |
| - } else if (!strcasecmp(classname, "stdclass") || !strcasecmp(classname, "object")) { |
979 |
| - map->array_type = PHONGO_TYPEMAP_NATIVE_OBJECT; |
980 |
| - } else { |
981 |
| - zend_class_entry *array_ce = zend_fetch_class(classname, classname_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC); |
982 |
| - map->array_type = PHONGO_TYPEMAP_CLASS; |
983 |
| - |
984 |
| - if (instanceof_function(array_ce, php_phongo_unserializable_ce TSRMLS_CC)) { |
985 |
| - map->array = array_ce; |
986 |
| - } |
987 |
| - } |
988 |
| - if (classname_free) { |
989 |
| - efree(classname); |
990 |
| - } |
| 1004 | + apply_classname_to_state(classname, classname_len, &map->array_type, &map->array TSRMLS_CC); |
| 1005 | + } |
| 1006 | + if (classname_free) { |
| 1007 | + str_efree(classname); |
991 | 1008 | }
|
992 | 1009 |
|
993 | 1010 | classname = php_array_fetchl_string(typemap, "document", sizeof("document")-1, &classname_len, &classname_free);
|
994 | 1011 | if (classname_len) {
|
995 |
| - if (!strcasecmp(classname, "array")) { |
996 |
| - map->document_type = PHONGO_TYPEMAP_NATIVE_ARRAY; |
997 |
| - } else if (!strcasecmp(classname, "stdclass") || !strcasecmp(classname, "object")) { |
998 |
| - map->document_type = PHONGO_TYPEMAP_NATIVE_OBJECT; |
999 |
| - } else { |
1000 |
| - zend_class_entry *document_ce = zend_fetch_class(classname, classname_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC); |
1001 |
| - map->document_type = PHONGO_TYPEMAP_CLASS; |
1002 |
| - |
1003 |
| - if (instanceof_function(document_ce, php_phongo_unserializable_ce TSRMLS_CC)) { |
1004 |
| - map->document = document_ce; |
1005 |
| - } |
1006 |
| - } |
1007 |
| - if (classname_free) { |
1008 |
| - efree(classname); |
1009 |
| - } |
| 1012 | + apply_classname_to_state(classname, classname_len, &map->document_type, &map->document TSRMLS_CC); |
| 1013 | + } |
| 1014 | + if (classname_free) { |
| 1015 | + str_efree(classname); |
1010 | 1016 | }
|
1011 | 1017 |
|
1012 | 1018 | classname = php_array_fetchl_string(typemap, "root", sizeof("root")-1, &classname_len, &classname_free);
|
1013 | 1019 | if (classname_len) {
|
1014 |
| - if (!strcasecmp(classname, "array")) { |
1015 |
| - map->root_type = PHONGO_TYPEMAP_NATIVE_ARRAY; |
1016 |
| - } else if (!strcasecmp(classname, "stdclass") || !strcasecmp(classname, "object")) { |
1017 |
| - map->root_type = PHONGO_TYPEMAP_NATIVE_OBJECT; |
1018 |
| - } else { |
1019 |
| - zend_class_entry *root_ce = zend_fetch_class(classname, classname_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC); |
1020 |
| - map->root_type = PHONGO_TYPEMAP_CLASS; |
1021 |
| - |
1022 |
| - if (instanceof_function(root_ce, php_phongo_unserializable_ce TSRMLS_CC)) { |
1023 |
| - map->root = root_ce; |
1024 |
| - } |
1025 |
| - } |
1026 |
| - if (classname_free) { |
1027 |
| - efree(classname); |
1028 |
| - } |
| 1020 | + apply_classname_to_state(classname, classname_len, &map->root_type, &map->root TSRMLS_CC); |
| 1021 | + } |
| 1022 | + if (classname_free) { |
| 1023 | + str_efree(classname); |
1029 | 1024 | }
|
1030 | 1025 | }
|
1031 | 1026 | }
|
| 1027 | + |
1032 | 1028 | /* {{{ proto array|object BSON\toPHP(string $bson [, array $typemap = array()])
|
1033 | 1029 | Returns the PHP representation of a BSON value, optionally converting it into a custom class */
|
1034 | 1030 | PHP_FUNCTION(toPHP)
|
|
0 commit comments