Read the manual. Define defined constants Allow only:
Only scalar and null are allowed. The type of the scalar is integer, Float,string, or Boolean. It is also possible to define the type of a constant value as resource, but this is not recommended, which may cause an unknown condition to occur.
Read the PHP source today, found that the second parameter of define can actually be an object.
First, put a sample:
Copy Code code as follows:
Class A {
Public Function __tostring () {
return ' bar ';
}
}
$a = new A ();
Define (' foo ', $a);
echo foo;
Output bar
Then look at how the Define in PHP is implemented:
Copy Code code as follows:
Zend_function (define)
{
Char *name;
int Name_len;
Zval *val;
Zval *val_free = NULL;
Zend_bool non_cs = 0;
int case_sensitive = Const_cs;
Zend_constant C;
Receive 3 parameters, String,zval,bool
if (Zend_parse_parameters (Zend_num_args () tsrmls_cc, "Sz|b", &name, &name_len, &val, &non_cs) = = Failure) {
Return
}
is case sensitive
if (Non_cs) {
case_sensitive = 0;
}
If the class constant is define, the error
if (ZEND_MEMNSTR (Name, "::", sizeof ("::")-1, name + Name_len)) {
Zend_error (e_warning, "Class constants cannot be defined or redefined");
Return_false;
}
Get the real value, save with Val
Repeat
Switch (Z_type_p (val)) {
Case Is_long:
Case Is_double:
Case is_string:
Case Is_bool:
Case Is_resource:
Case Is_null:
Break
Case Is_object:
if (!val_free) {
if (Z_obj_ht_p (val)->get) {
Val_free = val = z_obj_ht_p (val)->get (Val tsrmls_cc);
Goto repeat;
else if (Z_obj_ht_p (val)->cast_object) {
Alloc_init_zval (Val_free);
if (Z_obj_ht_p (Val)->cast_object (Val, Val_free, is_string tsrmls_cc) = = SUCCESS) {
val = val_free;
Break
}
}
}
* No Break * *
Default
Zend_error (e_warning, "Constants may only evaluate to scalar values");
if (Val_free) {
Zval_ptr_dtor (&val_free);
}
Return_false;
}
Building constants
C.value = *val;
Zval_copy_ctor (&c.value);
if (Val_free) {
Zval_ptr_dtor (&val_free);
}
C.flags = case_sensitive; /* Non Persistent * *
C.name = zend_strndup (name, Name_len);
C.name_len = name_len+1;
C.module_number = php_user_constant;
Registering constants
if (Zend_register_constant (&c tsrmls_cc) = = SUCCESS) {
Return_true;
} else {
Return_false;
}
}
Note that a cycle begins with repeat, and a goto statement is used T_T
The function of this code is:
For Int,float,string,bool,resource,null, these values are used directly when the constants are actually defined
For object, you need to convert object to one of these 6 types (if you are still object after the transition, continue the transformation)
How do you make object into one of 6 types? There are 2 ways to look at the code:
Copy Code code as follows:
if (Z_obj_ht_p (val)->get) {
Val_free = val = z_obj_ht_p (val)->get (Val tsrmls_cc);
Goto repeat;
}
The __tostring () method is called in Cast_object
else if (Z_obj_ht_p (val)->cast_object) {
Alloc_init_zval (Val_free);
if (Z_obj_ht_p (Val)->cast_object (Val, Val_free, is_string tsrmls_cc) = = SUCCESS)
{
val = val_free;
Break
}
}
1,z_obj_ht_p (Val)->get, after which the macro expands (*val). Value.obj.handlers->get
2,z_obj_ht_p (Val)->cast_object, after which the macro expands (*val). Value.obj.handlers->cast_object
Handlers is a structure that contains a number of function pointers, which are defined in _zend_object_handlers. The function pointers in this structure are all used to manipulate objects, such as reading/modifying object properties, getting/invoking object methods, and so on ... Get and Cast_object are also one of them.
For generic objects, PHP provides a standard Cast_object function zend_std_cast_object_tostring, where the code is located in PHP-SRC/ZEND/ZEND-OBJECT-HANDLERS.C:
Copy Code code as follows:
Zend_api int zend_std_cast_object_tostring (zval *readobj, zval *writeobj, int type TSRMLS_DC)/* {{* * *
{
Zval *retval;
Zend_class_entry *ce;
Switch (type) {
Case is_string:
CE = z_objce_p (readobj);
If __tostring is defined in the user's class, an attempt is made to invoke the
if (ce->__tostring &&
(Zend_call_method_with_0_params (&readobj, CE, &ce->__tostring, "__tostring", &retval) | | EG (Exception)) {
......
}
return failure;
......
}
return failure;
}
From the above realization, the default cast_object is to find the __tostring method in class and then call ...
Back to the first example, define (' foo ', $a), because $a is an instance of a, and Class A defines __tostring, so the Foo constant equals the return value bar of toString.