Here's a patch. You can compile this and add it yourself. Obviously, your code won't be portable.
Code: Select all
Index: ext/json/json.c
===================================================================
--- ext/json/json.c (revision 289904)
+++ ext/json/json.c (working copy)
@@ -176,6 +176,7 @@
{
int i, r;
HashTable *myht;
+ zend_class_entry *ce = NULL;
if (Z_TYPE_PP(val) == IS_ARRAY) {
myht = HASH_OF(*val);
@@ -183,6 +184,10 @@
} else {
myht = Z_OBJPROP_PP(val);
r = PHP_JSON_OUTPUT_OBJECT;
+
+ if (Z_OBJ_HT_PP(val)->get_class_entry) {
+ ce = Z_OBJCE_PP(val);
+ }
}
if (myht && myht->nApplyCount > 1) {
@@ -215,6 +220,15 @@
if (i == HASH_KEY_NON_EXISTANT)
break;
+ if (ce && i == HASH_KEY_IS_STRING) {
+ zend_property_info *property_info;
+ if (zend_hash_find(&ce->properties_info, key, key_len, (void**) &property_info) == SUCCESS) {
+ if ((property_info->flags & ZEND_ACC_TRANSIENT) == ZEND_ACC_TRANSIENT) {
+ continue;
+ }
+ }
+ }
+
if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) == SUCCESS) {
tmp_ht = HASH_OF(*data);
if (tmp_ht) {
Index: ext/json/tests/008.phpt
===================================================================
--- ext/json/tests/008.phpt (revision 0)
+++ ext/json/tests/008.phpt (revision 0)
@@ -0,0 +1,22 @@
+--TEST--
+Test json_encode() with transient properties
+--FILE--
+<?php
+
+class members
+{
+ private $var_private = 10;
+ protected $var_protected = "string";
+ public $var_public = array(-100.123, "string", TRUE);
+ public transient $var_public_transient = "SECRET";
+}
+
+var_dump(json_encode(new members()));
+
+echo "\nDone";
+?>
+--EXPECTF--
+
+string(39) "{"var_public":[-100.123,"string",true]}"
+
+Done
Index: ext/standard/tests/serialize/serialization_objects_016.phpt
===================================================================
--- ext/standard/tests/serialize/serialization_objects_016.phpt (revision 0)
+++ ext/standard/tests/serialize/serialization_objects_016.phpt (revision 0)
@@ -0,0 +1,64 @@
+--TEST--
+Test serialize() & unserialize() functions: objects with transients
+--FILE--
+<?php
+
+echo "\n--- Testing objects ---\n";
+
+class members
+{
+ private $var_private = 10;
+ protected $var_protected = "string";
+ public $var_public = array(-100.123, "string", TRUE);
+ public transient $var_public_transient = "SECRET";
+}
+
+$members_obj = new members();
+var_dump( $members_obj );
+$serialize_data = serialize( $members_obj );
+var_dump( $serialize_data );
+$members_obj = unserialize( $serialize_data );
+var_dump( $members_obj );
+
+echo "\nDone";
+?>
+--EXPECTF--
+
+--- Testing objects ---
+object(members)#%d (4) {
+ ["var_private":"members":private]=>
+ int(10)
+ ["var_protected":protected]=>
+ string(6) "string"
+ ["var_public"]=>
+ array(3) {
+ [0]=>
+ float(-100.123)
+ [1]=>
+ string(6) "string"
+ [2]=>
+ bool(true)
+ }
+ ["var_public_transient"]=>
+ string(6) "SECRET"
+}
+string(195) "O:7:"members":3:{s:20:" members var_private";i:10;s:16:" * var_protected";s:6:"string";s:10:"var_public";a:3:{i:0;d:-100.1230000000000046611603465862572193145751953125;i:1;s:6:"string";i:2;b:1;}}"
+object(members)#%d (4) {
+ ["var_private":"members":private]=>
+ int(10)
+ ["var_protected":protected]=>
+ string(6) "string"
+ ["var_public"]=>
+ array(3) {
+ [0]=>
+ float(-100.123)
+ [1]=>
+ string(6) "string"
+ [2]=>
+ bool(true)
+ }
+ ["var_public_transient"]=>
+ string(6) "SECRET"
+}
+
+Done
Index: ext/standard/var.c
===================================================================
--- ext/standard/var.c (revision 289904)
+++ ext/standard/var.c (working copy)
@@ -741,44 +741,62 @@
}
case IS_ARRAY: {
zend_bool incomplete_class = 0;
+ zend_class_entry *ce = NULL;
+
if (Z_TYPE_P(struc) == IS_ARRAY) {
smart_str_appendl(buf, "a:", 2);
myht = HASH_OF(struc);
} else {
incomplete_class = php_var_serialize_class_name(buf, struc TSRMLS_CC);
myht = Z_OBJPROP_P(struc);
+
+ if (Z_OBJ_HT_P(struc)->get_class_entry) {
+ ce = Z_OBJCE_P(struc);
+ }
}
+
/* count after serializing name, since php_var_serialize_class_name
* changes the count if the variable is incomplete class */
i = myht ? zend_hash_num_elements(myht) : 0;
- if (i > 0 && incomplete_class) {
- --i;
- }
- smart_str_append_long(buf, i);
- smart_str_appendl(buf, ":{", 2);
+
if (i > 0) {
char *key;
zval **data;
ulong index;
uint key_len;
+ int key_type = 0;
HashPosition pos;
+ smart_str array_buf = {0};
zend_hash_internal_pointer_reset_ex(myht, &pos);
for (;; zend_hash_move_forward_ex(myht, &pos)) {
- i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos);
- if (i == HASH_KEY_NON_EXISTANT) {
- break;
+ key_type = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos);
+
+ if (key_type == HASH_KEY_NON_EXISTANT) {
+ goto finish_encoding;
}
+
if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) {
+ --i;
continue;
}
- switch (i) {
+ if (ce && key_type == HASH_KEY_IS_STRING) {
+ zend_property_info *property_info;
+ if (zend_hash_find(&ce->properties_info, key, key_len, (void**) &property_info) == SUCCESS) {
+ if ((property_info->flags & ZEND_ACC_TRANSIENT) == ZEND_ACC_TRANSIENT) {
+ --i;
+ continue;
+ }
+ }
+ }
+
+ switch (key_type) {
case HASH_KEY_IS_LONG:
- php_var_serialize_long(buf, index);
+ php_var_serialize_long(&array_buf, index);
break;
case HASH_KEY_IS_STRING:
- php_var_serialize_string(buf, key, key_len - 1);
+ php_var_serialize_string(&array_buf, key, key_len - 1);
break;
}
@@ -789,18 +807,27 @@
|| data == &struc
|| (Z_TYPE_PP(data) == IS_ARRAY && Z_ARRVAL_PP(data)->nApplyCount > 1)
) {
- smart_str_appendl(buf, "N;", 2);
+ smart_str_appendl(&array_buf, "N;", 2);
} else {
if (Z_TYPE_PP(data) == IS_ARRAY) {
Z_ARRVAL_PP(data)->nApplyCount++;
}
- php_var_serialize_intern(buf, *data, var_hash TSRMLS_CC);
+ php_var_serialize_intern(&array_buf, *data, var_hash TSRMLS_CC);
if (Z_TYPE_PP(data) == IS_ARRAY) {
Z_ARRVAL_PP(data)->nApplyCount--;
}
}
}
+finish_encoding:
+ smart_str_append_long(buf, i);
+ smart_str_appendl(buf, ":{", 2);
+ smart_str_appendl(buf, array_buf.c, array_buf.len);
+ smart_str_free(&array_buf);
+ } else {
+ smart_str_append_long(buf, i);
+ smart_str_appendl(buf, ":{", 2);
}
+
smart_str_appendc(buf, '}');
return;
}
Index: Zend/tests/access_modifiers_013.phpt
===================================================================
--- Zend/tests/access_modifiers_013.phpt (revision 0)
+++ Zend/tests/access_modifiers_013.phpt (revision 0)
@@ -0,0 +1,13 @@
+--TEST--
+Transient properties
+--FILE--
+<?php
+class Hobo {
+ public transient $moveAlongNow = 'Spare some change?';
+}
+
+echo "Done\n";
+
+?>
+--EXPECTF--
+Done
Index: Zend/zend_language_scanner.l
===================================================================
--- Zend/zend_language_scanner.l (revision 289904)
+++ Zend/zend_language_scanner.l (working copy)
@@ -1142,6 +1142,10 @@
return T_PUBLIC;
}
+<ST_IN_SCRIPTING>"transient" {
+ return T_TRANSIENT;
+}
+
<ST_IN_SCRIPTING>"unset" {
return T_UNSET;
}
Index: Zend/zend_language_parser.y
===================================================================
--- Zend/zend_language_parser.y (revision 289904)
+++ Zend/zend_language_parser.y (working copy)
@@ -114,7 +114,7 @@
%token T_THROW
%token T_USE
%token T_GLOBAL
-%right T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC
+%right T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC T_TRANSIENT
%token T_VAR
%token T_UNSET
%token T_ISSET
@@ -546,6 +546,7 @@
| T_STATIC { Z_LVAL($$.u.constant) = ZEND_ACC_STATIC; }
| T_ABSTRACT { Z_LVAL($$.u.constant) = ZEND_ACC_ABSTRACT; }
| T_FINAL { Z_LVAL($$.u.constant) = ZEND_ACC_FINAL; }
+ | T_TRANSIENT { Z_LVAL($$.u.constant) = ZEND_ACC_TRANSIENT; }
;
class_variable_declaration:
Index: Zend/zend_compile.h
===================================================================
--- Zend/zend_compile.h (revision 289904)
+++ Zend/zend_compile.h (working copy)
@@ -112,6 +112,7 @@
#define ZEND_ACC_ABSTRACT 0x02
#define ZEND_ACC_FINAL 0x04
#define ZEND_ACC_IMPLEMENTED_ABSTRACT 0x08
+#define ZEND_ACC_TRANSIENT 0x10
/* class flags (types) */
/* ZEND_ACC_IMPLICIT_ABSTRACT_CLASS is used for abstract classes (since it is set by any abstract method even interfaces MAY have it set, too). */
A discussion about whether the PHP Core should or should not be customized is drifting
(Couldn't resist using that "smilie"). If you'd like to have that discussion, could you submit a new topic? Thanks!