As per bug #34199 and as Rob points out, if($obj) and if(!$obj) are
handled by different opcodes and these two opcodes are inconsistent in
whether they call an object's cast_object handler.
if($obj) results in a ZEND_JMPZ_SPEC_CV_HANDLER which calls
i_zend_is_true() which always return true for objects, no matter what
(ignore compatibility mode here) because of this code in zend_execute.h:
case IS_OBJECT:
if(IS_ZEND_STD_OBJECT(*op)) {
TSRMLS_FETCH();
if(EG(ze1_compatibility_mode)) {
result = (zend_hash_num_elements(Z_OBJPROP_P(op))?1:0);
} else {
result = 1;
}
} else {
result = 1;
}
break;
if(!$obj) results in a which calls convert_to_boolean() which in turn
calls convert_object_to_type() which has:
if (Z_OBJ_HT_P(op)->cast_object) {
if (Z_OBJ_HT_P(op)->cast_object(op, op, ctype, 1 TSRMLS_CC) ==
SUCCESS) {
op->type = ctype;
}
This means that any object which actually implements a cast_object
handler that returns false under some condition will be broken. The
simple example is:
$a = simplexml_load_string('<a></a>');
if($a && !$a) echo "BUG!";
I think we need to fix i_zend_is_true's IS_OBJECT case to check to see
if the object has a cast_object handler and call it or just call
convert_to_boolean() there. Or we need to clean this up and not have
such different codepaths for these two cases.
-Rasmus
if(!$obj) results in a which calls convert_to_boolean() which in turn
calls convert_object_to_type() which has:
I meant results in a ZEND_BOOL_NOT_SPEC_CV_HANDLER...
Yep I think that's a good point.
Checking for cast is the right thing IMO.
At 02:45 PM 8/24/2005, Rasmus Lerdorf wrote:
As per bug #34199 and as Rob points out, if($obj) and if(!$obj) are
handled by different opcodes and these two opcodes are inconsistent in
whether they call an object's cast_object handler.if($obj) results in a ZEND_JMPZ_SPEC_CV_HANDLER which calls
i_zend_is_true() which always return true for objects, no matter what
(ignore compatibility mode here) because of this code in zend_execute.h:case IS_OBJECT: if(IS_ZEND_STD_OBJECT(*op)) { TSRMLS_FETCH(); if(EG(ze1_compatibility_mode)) { result = (zend_hash_num_elements(Z_OBJPROP_P(op))?1:0); } else { result = 1; } } else { result = 1; } break;if(!$obj) results in a which calls convert_to_boolean() which in turn
calls convert_object_to_type() which has:if (Z_OBJ_HT_P(op)->cast_object) {
if (Z_OBJ_HT_P(op)->cast_object(op, op, ctype, 1 TSRMLS_CC) ==SUCCESS) {
op->type = ctype;}This means that any object which actually implements a cast_object
handler that returns false under some condition will be broken. The
simple example is:$a = simplexml_load_string('<a></a>');
if($a && !$a) echo "BUG!";I think we need to fix i_zend_is_true's IS_OBJECT case to check to see
if the object has a cast_object handler and call it or just call
convert_to_boolean() there. Or we need to clean this up and not have
such different codepaths for these two cases.-Rasmus
Hello Andi,
in that case we are providing a default conversion, maybe like the old
one? Or just always return 1 like we do in 5.0 ?
marcus
Thursday, August 25, 2005, 1:31:08 AM, you wrote:
Yep I think that's a good point.
Checking for cast is the right thing IMO.
At 02:45 PM 8/24/2005, Rasmus Lerdorf wrote:
As per bug #34199 and as Rob points out, if($obj) and if(!$obj) are
handled by different opcodes and these two opcodes are inconsistent in
whether they call an object's cast_object handler.if($obj) results in a ZEND_JMPZ_SPEC_CV_HANDLER which calls
i_zend_is_true() which always return true for objects, no matter what
(ignore compatibility mode here) because of this code in zend_execute.h:case IS_OBJECT: if(IS_ZEND_STD_OBJECT(*op)) { TSRMLS_FETCH(); if(EG(ze1_compatibility_mode)) { result =(zend_hash_num_elements(Z_OBJPROP_P(op))?1:0);
} else {
result = 1;
}
} else {
result = 1;
}
break;if(!$obj) results in a which calls convert_to_boolean() which in turn
calls convert_object_to_type() which has:if (Z_OBJ_HT_P(op)->cast_object) {
if (Z_OBJ_HT_P(op)->cast_object(op, op, ctype, 1 TSRMLS_CC) ==SUCCESS) {
op->type = ctype;}This means that any object which actually implements a cast_object
handler that returns false under some condition will be broken. The
simple example is:$a = simplexml_load_string('<a></a>');
if($a && !$a) echo "BUG!";I think we need to fix i_zend_is_true's IS_OBJECT case to check to see
if the object has a cast_object handler and call it or just call
convert_to_boolean() there. Or we need to clean this up and not have
such different codepaths for these two cases.
Yep, the default for an instantiated object should be true (i.e. it's
not null).
Andi
At 12:14 AM 8/25/2005, Marcus Boerger wrote:
Hello Andi,
in that case we are providing a default conversion, maybe like the old
one? Or just always return 1 like we do in 5.0 ?marcus
Thursday, August 25, 2005, 1:31:08 AM, you wrote:
Yep I think that's a good point.
Checking for cast is the right thing IMO.At 02:45 PM 8/24/2005, Rasmus Lerdorf wrote:
As per bug #34199 and as Rob points out, if($obj) and if(!$obj) are
handled by different opcodes and these two opcodes are inconsistent in
whether they call an object's cast_object handler.if($obj) results in a ZEND_JMPZ_SPEC_CV_HANDLER which calls
i_zend_is_true() which always return true for objects, no matter what
(ignore compatibility mode here) because of this code in zend_execute.h:case IS_OBJECT: if(IS_ZEND_STD_OBJECT(*op)) { TSRMLS_FETCH(); if(EG(ze1_compatibility_mode)) { result =(zend_hash_num_elements(Z_OBJPROP_P(op))?1:0);
} else {
result = 1;
}
} else {
result = 1;
}
break;if(!$obj) results in a which calls convert_to_boolean() which in turn
calls convert_object_to_type() which has:if (Z_OBJ_HT_P(op)->cast_object) {
if (Z_OBJ_HT_P(op)->cast_object(op, op, ctype, 1 TSRMLS_CC) ==SUCCESS) {
op->type = ctype;}This means that any object which actually implements a cast_object
handler that returns false under some condition will be broken. The
simple example is:$a = simplexml_load_string('<a></a>');
if($a && !$a) echo "BUG!";I think we need to fix i_zend_is_true's IS_OBJECT case to check to see
if the object has a cast_object handler and call it or just call
convert_to_boolean() there. Or we need to clean this up and not have
such different codepaths for these two cases.