Properties

Access control within PHP5 object properties is handled somewhat differently than method visibility. When declaring a public property within the standard property table, you can use the zend_hash_add() or add_property_*() family functions just as you would ordinarily expect to.

For protected and private properties, however, a new Zend API function is required:

void zend_mangle_property_name(char **dest, int *dest_length, char *class, int class_length, char *prop, int prop_length, int persistent)

This function will allocate a new chunk or memory and construct a string according to the layout: classnamepropname. If classname is a specific classname, such as Sample3_SecondClass, the property will have private visibilityIt will only be visible from within instances of Sample3_SecondClass objects.

If classname is specified as simply *, the property will have protected visibility and be accessible from any ancestor or descendant of the object instance's class. In practice, properties might be added to an object in the following manner:

void php_sample3_addprops(zval *objvar) { char *propname; int propname_len; /* Public */ add_property_long(objvar, "Chapter", 11); /* Protected */ zend_mangle_property_name(&propname, &propname_len, "*", 1, "Title", sizeof("Title")-1, 0); add_property_string_ex(objvar, propname, propname_len, "PHP5 Objects", 1 TSRMLS_CC); efree(propname); /* Private */ zend_mangle_property_name(&propname, &propname_len, "Sample3_SecondClass",sizeof("Sample3_SecondClass")-1, "Section", sizeof("Section")-1, 0); add_property_string_ex(objvar, propname, propname_len, "Properties", 1 TSRMLS_CC); efree(propname); }

By using the _ex() version of the add_property_*() family of functions, you're able to explicitly identify the length of the property name string. This is necessary because the NULL bytes in protected and private property names would otherwise fool strlen() into thinking that you'd passed zero-length prop names. Notice also that the _ex() version of the add_property_*() functions require TSRMLS_CC to be explicitly passed. Ordinarily, this would be implicitly passed through macro expansion.

Constants

Declaring class constants is much like declaring object properties. The key difference between the two comes from their persistency because properties can wait until instantiation, which occurs during a request, while constants are tied directly to the class definition and are only declared during the MINIT phase.

Because the standard zval* manipulation macros and functions assume nonpersistency, you'll need to write a fair amount of code manually. Consider the following function, which might be called following class registration:

void php_sample3_register_constants(zend_class_entry *ce) { zval *constval; /* Basic scalar values can use Z_*() to set their value */ constval = pemalloc(sizeof(zval), 1); INIT_PZVAL(constval); ZVAL_DOUBLE(constval, 2.7182818284); zend_hash_add(&ce->constants_table, "E", sizeof("E"), (void*)&constval, sizeof(zval*), NULL); /* Strings require additional mallocs */ constval = pemalloc(sizeof(zval), 1); INIT_PZVAL(constval); Z_TYPE_P(constval) = IS_STRING; Z_STRLEN_P(constval) = sizeof("Hello World") - 1; Z_STRVAL_P(constval) = pemalloc(Z_STRLEN_P(constval)+1, 1); memcpy(Z_STRVAL_P(constval), "Hello World", Z_STRLEN_P(constval) + 1); zend_hash_add(&ce->constants_table, "GREETING", sizeof("GREETING"), (void*)&constval, sizeof(zval*), NULL); /* Objects, Arrays, and Resources can't be constants */ } PHP_MINIT_FUNCTION(sample3) { zend_class_entry ce; INIT_CLASS_ENTRY(ce, PHP_SAMPLE3_SC_NAME, php_sample3_sc_functions); php_sample3_sc_entry = zend_register_internal_class(&ce TSRMLS_CC); php_sample3_register_constants(php_sample3_sc_entry); return SUCCESS; }

Following this addition, these class constants can be accessed without instantiation via Sample3_SecondClass::E and Sample3_SecondClass::GREETING, respectively.

Категории