Hello Felipe,
I do not like readonly, instead I would prefer a version where read and
write have separate visibility. And actually your idea seems to prevent a
second write to the value, using NULL as for detection means. Now what
happens is that a) a property that has a default value will become a const,
yet with some trickery (array conversion, ArrayObject) allowing to be
ignored. And b) when set to NULL you can do another write until you do a non
NULL write. All that said, here is my idea again:
class Foo {
private : public $bar = "baz";
This does:
a) not introduce a new keyword
b) have write access private and read access public
c) is compatible with all we have right now
d) could be limited to public on the read side
(ze2-readable_properties-20060514d.diff.txt).
I even had a patch in may 2006 (ze2-readable_properties-20060516.diff.txt)
that implements the new visibility promulgate (which i thought of as a funny
solution to public read).
marcus
Wednesday, February 13, 2008, 11:18:17 AM, you wrote:
> Em Qua, 2008-02-13 às 10:59 +0100, Sebastian Schneider escreveu:
>> By the way, when declared final the value couldn't be changed, anyways -
>> however it MUST be read-only.
> I made a ***simple*** (or wrong!) patch months ago for read-only
> property as you described.
> http://felipe.ath.cx/diff/readonly.patch
> e.g.
> class foo {
> private readonly $foo = array(1, 2, 3);
> }
> But i agree with early discussions, and with Marcus' implementation:
> http://marc.info/?l=php-internals&w=2&r=1&s=readonly&q=b
Best regards,
Marcus
Index: Zend/zend_compile.h
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.h,v
retrieving revision 1.316.2.8.2.2
diff -u -p -d -r1.316.2.8.2.2 zend_compile.h
--- Zend/zend_compile.h 11 May 2006 21:07:39 -0000 1.316.2.8.2.2
+++ Zend/zend_compile.h 16 May 2006 21:38:41 -0000
@@ -139,6 +139,10 @@ typedef struct _zend_try_catch_element {
/* deprecation flag */
#define ZEND_ACC_DEPRECATED 0x40000
+/* property handling control */
+#define ZEND_ACC_READ_ONLY 0x080000
+#define ZEND_ACC_PUB_READ 0x100000
+
char *zend_visibility_string(zend_uint fn_flags);
Index: Zend/zend_language_parser.y
===================================================================
RCS file: /repository/ZendEngine2/zend_language_parser.y,v
retrieving revision 1.160.2.4.2.1
diff -u -p -d -r1.160.2.4.2.1 zend_language_parser.y
--- Zend/zend_language_parser.y 11 May 2006 21:07:39 -0000 1.160.2.4.2.1
+++ Zend/zend_language_parser.y 16 May 2006 21:38:41 -0000
@@ -115,7 +115,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_PROMULGATE
%token T_VAR
%token T_UNSET
%token T_ISSET
@@ -500,8 +500,9 @@ method_body:
;
variable_modifiers:
- non_empty_member_modifiers { $$ = $1; }
- | T_VAR {
Z_LVAL($$.u.constant) = ZEND_ACC_PUBLIC; }
+ non_empty_member_modifiers { $$ =
$1; }
+ | non_empty_member_modifiers T_PROMULGATE { $$ = $1;
Z_LVAL($$.u.constant) |= ZEND_ACC_PUB_READ; }
+ | T_VAR
{ Z_LVAL($$.u.constant) = ZEND_ACC_PUBLIC; }
;
method_modifiers:
Index: Zend/zend_language_scanner.l
===================================================================
RCS file: /repository/ZendEngine2/zend_language_scanner.l,v
retrieving revision 1.131.2.11
diff -u -p -d -r1.131.2.11 zend_language_scanner.l
--- Zend/zend_language_scanner.l 13 Apr 2006 13:48:28 -0000
1.131.2.11
+++ Zend/zend_language_scanner.l 16 May 2006 21:38:42 -0000
@@ -1063,6 +1063,10 @@ NEWLINE ("\r"|"\n"|"\r\n")
return T_PUBLIC;
}
+<ST_IN_SCRIPTING>"promulgate" {
+ return T_PROMULGATE;
+}
+
<ST_IN_SCRIPTING>"unset" {
return T_UNSET;
}
Index: Zend/zend_object_handlers.c
===================================================================
RCS file: /repository/ZendEngine2/zend_object_handlers.c,v
retrieving revision 1.135.2.6.2.2
diff -u -p -d -r1.135.2.6.2.2 zend_object_handlers.c
--- Zend/zend_object_handlers.c 10 May 2006 21:12:48 -0000 1.135.2.6.2.2
+++ Zend/zend_object_handlers.c 16 May 2006 21:38:42 -0000
@@ -144,20 +144,26 @@ static zval *zend_std_call_issetter(zval
return retval;
}
-static int zend_verify_property_access(zend_property_info *property_info,
zend_class_entry *ce TSRMLS_DC)
+static int zend_verify_property_access(zend_property_info *property_info,
zend_class_entry *ce, int read_write TSRMLS_DC)
{
+ if (!read_write && (property_info->flags & ZEND_ACC_READ_ONLY)) {
+ return 0;
+ }
switch (property_info->flags & ZEND_ACC_PPP_MASK) {
case ZEND_ACC_PUBLIC:
return 1;
case ZEND_ACC_PROTECTED:
- return zend_check_protected(ce, EG(scope));
+ if ((property_info->flags & ZEND_ACC_PUB_READ) &&
read_write) {
+ return 1;
+ } else {
+ return zend_check_protected(ce, EG(scope));
+ }
case ZEND_ACC_PRIVATE:
- if (ce==EG(scope) && EG(scope)) {
+ if ((ce == EG(scope) && ce) || ((property_info->flags &
ZEND_ACC_PUB_READ) && read_write)) {
return 1;
} else {
return 0;
}
- break;
}
return 0;
}
@@ -175,7 +181,7 @@ static inline zend_bool is_derived_class
return 0;
}
-ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry
*ce, zval *member, int silent TSRMLS_DC)
+ZEND_API struct _zend_property_info
*zend_get_property_info_ex(zend_class_entry *ce, zval *member, int silent, int
read_write TSRMLS_DC)
{
zend_property_info *property_info = NULL;
zend_property_info *scope_property_info;
@@ -198,7 +204,7 @@ ZEND_API struct _zend_property_info *zen
/* if it's a shadow - go to access it's private */
property_info = NULL;
} else {
- if (zend_verify_property_access(property_info, ce
TSRMLS_CC)) {
+ if (zend_verify_property_access(property_info, ce,
read_write TSRMLS_CC)) {
if (property_info->flags & ZEND_ACC_CHANGED
&& !(property_info->flags &
ZEND_ACC_PRIVATE)) {
/* We still need to make sure that
we're not in a context
@@ -244,6 +250,11 @@ ZEND_API struct _zend_property_info *zen
}
+ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry
*ce, zval *member, int silent TSRMLS_DC)
+{
+ return zend_get_property_info_ex(ce, member, silent, 0 TSRMLS_CC);
+}
+
ZEND_API int zend_check_property_access(zend_object *zobj, char
*prop_info_name TSRMLS_DC)
{
zend_property_info *property_info;
@@ -252,7 +263,7 @@ ZEND_API int zend_check_property_access(
zend_unmangle_property_name(prop_info_name, &class_name, &prop_name);
ZVAL_STRING(&member, prop_name, 0);
- property_info = zend_get_property_info(zobj->ce, &member, 1 TSRMLS_CC);
+ property_info = zend_get_property_info_ex(zobj->ce, &member, 1, 0
TSRMLS_CC);
if (!property_info) {
return FAILURE;
}
@@ -265,7 +276,7 @@ ZEND_API int zend_check_property_access(
return FAILURE;
}
}
- return zend_verify_property_access(property_info, zobj->ce TSRMLS_CC) ?
SUCCESS : FAILURE;
+ return zend_verify_property_access(property_info, zobj->ce, 1
TSRMLS_CC) ? SUCCESS : FAILURE;
}
static int zend_get_property_guard(zend_object *zobj, zend_property_info
*property_info, zval *member, zend_guard **pguard)
@@ -318,7 +329,7 @@ zval *zend_std_read_property(zval *objec
#endif
/* make zend_get_property_info silent if we have getter - we may want
to use it */
- property_info = zend_get_property_info(zobj->ce, member,
(zobj->ce->__get != NULL) TSRMLS_CC);
+ property_info = zend_get_property_info_ex(zobj->ce, member,
(zobj->ce->__get != NULL), 1 TSRMLS_CC);
if (!property_info || zend_hash_quick_find(zobj->properties,
property_info->name, property_info->name_length+1, property_info->h, (void **)
&retval) == FAILURE) {
zend_guard *guard;
@@ -371,7 +382,7 @@ static void zend_std_write_property(zval
member = tmp_member;
}
- property_info = zend_get_property_info(zobj->ce, member,
(zobj->ce->__set != NULL) TSRMLS_CC);
+ property_info = zend_get_property_info_ex(zobj->ce, member,
(zobj->ce->__set != NULL), 0 TSRMLS_CC);
if (property_info && zend_hash_quick_find(zobj->properties,
property_info->name, property_info->name_length+1, property_info->h, (void **)
&variable_ptr) == SUCCESS) {
if (*variable_ptr == value) {
@@ -526,7 +537,7 @@ static zval **zend_std_get_property_ptr_
fprintf(stderr, "Ptr object #%d property: %s\n",
Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
#endif
- property_info = zend_get_property_info(zobj->ce, member,
(zobj->ce->__get != NULL) TSRMLS_CC);
+ property_info = zend_get_property_info_ex(zobj->ce, member,
(zobj->ce->__get != NULL), 0 TSRMLS_CC);
if (!property_info || zend_hash_quick_find(zobj->properties,
property_info->name, property_info->name_length+1, property_info->h, (void **)
&retval) == FAILURE) {
zval *new_zval;
@@ -570,7 +581,7 @@ static void zend_std_unset_property(zval
member = tmp_member;
}
- property_info = zend_get_property_info(zobj->ce, member,
(zobj->ce->__unset != NULL) TSRMLS_CC);
+ property_info = zend_get_property_info_ex(zobj->ce, member,
(zobj->ce->__unset != NULL), 0 TSRMLS_CC);
if (!property_info || zend_hash_del(zobj->properties,
property_info->name, property_info->name_length+1) == FAILURE) {
zend_guard *guard;
@@ -849,7 +860,7 @@ ZEND_API zval **zend_std_get_static_prop
zend_printf("Access type for %s::%s is %s\n", ce->name, property_name,
zend_visibility_string(property_info->flags));
#endif
- if (!zend_verify_property_access(property_info, ce TSRMLS_CC)) {
+ if (!zend_verify_property_access(property_info, ce, 1 TSRMLS_CC)) {
if (!silent) {
zend_error(E_ERROR, "Cannot access %s property
%s::$%s", zend_visibility_string(property_info->flags), ce->name,
property_name);
}
@@ -945,7 +956,7 @@ static int zend_std_has_property(zval *o
fprintf(stderr, "Read object #%d property: %s\n",
Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
#endif
- property_info = zend_get_property_info(zobj->ce, member, 1 TSRMLS_CC);
+ property_info = zend_get_property_info_ex(zobj->ce, member, 1, 0
TSRMLS_CC);
if (!property_info || zend_hash_quick_find(zobj->properties,
property_info->name, property_info->name_length+1, property_info->h, (void **)
&value) == FAILURE) {
zend_guard *guard;
Index: Zend/zend_object_handlers.h
===================================================================
RCS file: /repository/ZendEngine2/zend_object_handlers.h,v
retrieving revision 1.47.2.2.2.1
diff -u -p -d -r1.47.2.2.2.1 zend_object_handlers.h
--- Zend/zend_object_handlers.h 9 May 2006 23:53:23 -0000 1.47.2.2.2.1
+++ Zend/zend_object_handlers.h 16 May 2006 21:38:42 -0000
@@ -140,6 +140,7 @@ BEGIN_EXTERN_C()
ZEND_API union _zend_function *zend_std_get_static_method(zend_class_entry
*ce, char *function_name_strval, int function_name_strlen TSRMLS_DC);
ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, char
*property_name, int property_name_len, zend_bool silent TSRMLS_DC);
ZEND_API zend_bool zend_std_unset_static_property(zend_class_entry *ce, char
*property_name, int property_name_len TSRMLS_DC);
+ZEND_API struct _zend_property_info
*zend_get_property_info_ex(zend_class_entry *ce, zval *member, int silent, int
read_write TSRMLS_DC);
ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry
*ce, zval *member, int silent TSRMLS_DC);
ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int
type TSRMLS_DC);
Index: Zend/zend_compile.h
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.h,v
retrieving revision 1.316.2.8.2.2
diff -u -p -d -r1.316.2.8.2.2 zend_compile.h
--- Zend/zend_compile.h 11 May 2006 21:07:39 -0000 1.316.2.8.2.2
+++ Zend/zend_compile.h 14 May 2006 19:58:11 -0000
@@ -139,6 +139,10 @@ typedef struct _zend_try_catch_element {
/* deprecation flag */
#define ZEND_ACC_DEPRECATED 0x40000
+/* property handling control */
+#define ZEND_ACC_READ_ONLY 0x080000
+#define ZEND_ACC_PUB_READ 0x100000
+
char *zend_visibility_string(zend_uint fn_flags);
Index: Zend/zend_language_parser.y
===================================================================
RCS file: /repository/ZendEngine2/zend_language_parser.y,v
retrieving revision 1.160.2.4.2.1
diff -u -p -d -r1.160.2.4.2.1 zend_language_parser.y
--- Zend/zend_language_parser.y 11 May 2006 21:07:39 -0000 1.160.2.4.2.1
+++ Zend/zend_language_parser.y 14 May 2006 19:58:12 -0000
@@ -500,8 +500,9 @@ method_body:
;
variable_modifiers:
- non_empty_member_modifiers { $$ = $1; }
- | T_VAR {
Z_LVAL($$.u.constant) = ZEND_ACC_PUBLIC; }
+ non_empty_member_modifiers { $$ =
$1; }
+ | non_empty_member_modifiers ':' T_PUBLIC { $$ = $1;
Z_LVAL($$.u.constant) |= ZEND_ACC_PUB_READ; }
+ | T_VAR
{ Z_LVAL($$.u.constant) = ZEND_ACC_PUBLIC; }
;
method_modifiers:
Index: Zend/zend_object_handlers.c
===================================================================
RCS file: /repository/ZendEngine2/zend_object_handlers.c,v
retrieving revision 1.135.2.6.2.2
diff -u -p -d -r1.135.2.6.2.2 zend_object_handlers.c
--- Zend/zend_object_handlers.c 10 May 2006 21:12:48 -0000 1.135.2.6.2.2
+++ Zend/zend_object_handlers.c 14 May 2006 19:58:12 -0000
@@ -144,20 +144,26 @@ static zval *zend_std_call_issetter(zval
return retval;
}
-static int zend_verify_property_access(zend_property_info *property_info,
zend_class_entry *ce TSRMLS_DC)
+static int zend_verify_property_access(zend_property_info *property_info,
zend_class_entry *ce, int read_write TSRMLS_DC)
{
+ if (!read_write && (property_info->flags & ZEND_ACC_READ_ONLY)) {
+ return 0;
+ }
switch (property_info->flags & ZEND_ACC_PPP_MASK) {
case ZEND_ACC_PUBLIC:
return 1;
case ZEND_ACC_PROTECTED:
- return zend_check_protected(ce, EG(scope));
+ if ((property_info->flags & ZEND_ACC_PUB_READ) &&
read_write) {
+ return 1;
+ } else {
+ return zend_check_protected(ce, EG(scope));
+ }
case ZEND_ACC_PRIVATE:
- if (ce==EG(scope) && EG(scope)) {
+ if ((ce == EG(scope) && ce) || ((property_info->flags &
ZEND_ACC_PUB_READ) && read_write)) {
return 1;
} else {
return 0;
}
- break;
}
return 0;
}
@@ -175,7 +181,7 @@ static inline zend_bool is_derived_class
return 0;
}
-ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry
*ce, zval *member, int silent TSRMLS_DC)
+ZEND_API struct _zend_property_info
*zend_get_property_info_ex(zend_class_entry *ce, zval *member, int silent, int
read_write TSRMLS_DC)
{
zend_property_info *property_info = NULL;
zend_property_info *scope_property_info;
@@ -198,7 +204,7 @@ ZEND_API struct _zend_property_info *zen
/* if it's a shadow - go to access it's private */
property_info = NULL;
} else {
- if (zend_verify_property_access(property_info, ce
TSRMLS_CC)) {
+ if (zend_verify_property_access(property_info, ce,
read_write TSRMLS_CC)) {
if (property_info->flags & ZEND_ACC_CHANGED
&& !(property_info->flags &
ZEND_ACC_PRIVATE)) {
/* We still need to make sure that
we're not in a context
@@ -244,6 +250,11 @@ ZEND_API struct _zend_property_info *zen
}
+ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry
*ce, zval *member, int silent TSRMLS_DC)
+{
+ return zend_get_property_info_ex(ce, member, silent, 0 TSRMLS_CC);
+}
+
ZEND_API int zend_check_property_access(zend_object *zobj, char
*prop_info_name TSRMLS_DC)
{
zend_property_info *property_info;
@@ -252,7 +263,7 @@ ZEND_API int zend_check_property_access(
zend_unmangle_property_name(prop_info_name, &class_name, &prop_name);
ZVAL_STRING(&member, prop_name, 0);
- property_info = zend_get_property_info(zobj->ce, &member, 1 TSRMLS_CC);
+ property_info = zend_get_property_info_ex(zobj->ce, &member, 1, 0
TSRMLS_CC);
if (!property_info) {
return FAILURE;
}
@@ -265,7 +276,7 @@ ZEND_API int zend_check_property_access(
return FAILURE;
}
}
- return zend_verify_property_access(property_info, zobj->ce TSRMLS_CC) ?
SUCCESS : FAILURE;
+ return zend_verify_property_access(property_info, zobj->ce, 1
TSRMLS_CC) ? SUCCESS : FAILURE;
}
static int zend_get_property_guard(zend_object *zobj, zend_property_info
*property_info, zval *member, zend_guard **pguard)
@@ -318,7 +329,7 @@ zval *zend_std_read_property(zval *objec
#endif
/* make zend_get_property_info silent if we have getter - we may want
to use it */
- property_info = zend_get_property_info(zobj->ce, member,
(zobj->ce->__get != NULL) TSRMLS_CC);
+ property_info = zend_get_property_info_ex(zobj->ce, member,
(zobj->ce->__get != NULL), 1 TSRMLS_CC);
if (!property_info || zend_hash_quick_find(zobj->properties,
property_info->name, property_info->name_length+1, property_info->h, (void **)
&retval) == FAILURE) {
zend_guard *guard;
@@ -371,7 +382,7 @@ static void zend_std_write_property(zval
member = tmp_member;
}
- property_info = zend_get_property_info(zobj->ce, member,
(zobj->ce->__set != NULL) TSRMLS_CC);
+ property_info = zend_get_property_info_ex(zobj->ce, member,
(zobj->ce->__set != NULL), 0 TSRMLS_CC);
if (property_info && zend_hash_quick_find(zobj->properties,
property_info->name, property_info->name_length+1, property_info->h, (void **)
&variable_ptr) == SUCCESS) {
if (*variable_ptr == value) {
@@ -526,7 +537,7 @@ static zval **zend_std_get_property_ptr_
fprintf(stderr, "Ptr object #%d property: %s\n",
Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
#endif
- property_info = zend_get_property_info(zobj->ce, member,
(zobj->ce->__get != NULL) TSRMLS_CC);
+ property_info = zend_get_property_info_ex(zobj->ce, member,
(zobj->ce->__get != NULL), 0 TSRMLS_CC);
if (!property_info || zend_hash_quick_find(zobj->properties,
property_info->name, property_info->name_length+1, property_info->h, (void **)
&retval) == FAILURE) {
zval *new_zval;
@@ -570,7 +581,7 @@ static void zend_std_unset_property(zval
member = tmp_member;
}
- property_info = zend_get_property_info(zobj->ce, member,
(zobj->ce->__unset != NULL) TSRMLS_CC);
+ property_info = zend_get_property_info_ex(zobj->ce, member,
(zobj->ce->__unset != NULL), 0 TSRMLS_CC);
if (!property_info || zend_hash_del(zobj->properties,
property_info->name, property_info->name_length+1) == FAILURE) {
zend_guard *guard;
@@ -849,7 +860,7 @@ ZEND_API zval **zend_std_get_static_prop
zend_printf("Access type for %s::%s is %s\n", ce->name, property_name,
zend_visibility_string(property_info->flags));
#endif
- if (!zend_verify_property_access(property_info, ce TSRMLS_CC)) {
+ if (!zend_verify_property_access(property_info, ce, 1 TSRMLS_CC)) {
if (!silent) {
zend_error(E_ERROR, "Cannot access %s property
%s::$%s", zend_visibility_string(property_info->flags), ce->name,
property_name);
}
@@ -945,7 +956,7 @@ static int zend_std_has_property(zval *o
fprintf(stderr, "Read object #%d property: %s\n",
Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
#endif
- property_info = zend_get_property_info(zobj->ce, member, 1 TSRMLS_CC);
+ property_info = zend_get_property_info_ex(zobj->ce, member, 1, 0
TSRMLS_CC);
if (!property_info || zend_hash_quick_find(zobj->properties,
property_info->name, property_info->name_length+1, property_info->h, (void **)
&value) == FAILURE) {
zend_guard *guard;
Index: Zend/zend_object_handlers.h
===================================================================
RCS file: /repository/ZendEngine2/zend_object_handlers.h,v
retrieving revision 1.47.2.2.2.1
diff -u -p -d -r1.47.2.2.2.1 zend_object_handlers.h
--- Zend/zend_object_handlers.h 9 May 2006 23:53:23 -0000 1.47.2.2.2.1
+++ Zend/zend_object_handlers.h 14 May 2006 19:58:12 -0000
@@ -140,6 +140,7 @@ BEGIN_EXTERN_C()
ZEND_API union _zend_function *zend_std_get_static_method(zend_class_entry
*ce, char *function_name_strval, int function_name_strlen TSRMLS_DC);
ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, char
*property_name, int property_name_len, zend_bool silent TSRMLS_DC);
ZEND_API zend_bool zend_std_unset_static_property(zend_class_entry *ce, char
*property_name, int property_name_len TSRMLS_DC);
+ZEND_API struct _zend_property_info
*zend_get_property_info_ex(zend_class_entry *ce, zval *member, int silent, int
read_write TSRMLS_DC);
ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry
*ce, zval *member, int silent TSRMLS_DC);
ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int
type TSRMLS_DC);
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php