mirror of
https://github.com/php/pecl-php-operator.git
synced 2026-03-23 22:52:09 +01:00
Add support for is_greater(_or_equal) back
Support still requires a patch to the runtime, but it's a really small patch now.
This commit is contained in:
@@ -44,6 +44,8 @@ The following overload methods are supported:
|
||||
| $o != $arg | `__is_not_equal($arg)` |
|
||||
| $o < $arg | `__is_smaller($arg)` |
|
||||
| $o <= $arg | `__is_smaller_or_equal($arg)` |
|
||||
| $o > $arg | `__is_greater($arg)` * |
|
||||
| $o >= $arg | `__is_greater_or_equal($arg)` * |
|
||||
| $o <=> $arg | `__cmp($arg)` |
|
||||
| ++$o | `__pre_inc()` |
|
||||
| $o++ | `__post_inc()` |
|
||||
@@ -63,4 +65,4 @@ The following overload methods are supported:
|
||||
| $o &= $arg | `__assign_bw_and($arg)` |
|
||||
| $o ^= $arg | `__assign_bw_xor($arg)` |
|
||||
|
||||
|
||||
* - `__is_greater()` and `__is_greater_or_equal()` require a rebuild of the main PHP runtime using the [included patch](php7-is_greater.diff). Withtout this patch, `$a > $b` is automatically remapped to `$b < $a` by the engine.
|
||||
|
||||
59
operator.c
59
operator.c
@@ -78,8 +78,16 @@ zval *get_zval_ptr_undef(zend_uchar op_type, znode_op op, zend_free_op *free_op,
|
||||
UNARY_ASSIGN_OPS(X) \
|
||||
BINARY_ASSIGN_OPS(X)
|
||||
|
||||
/* greater/greater-equal are encoded as smaller/smaller-equal
|
||||
* so they require special handling
|
||||
*/
|
||||
#define GREATER_OPS(X) \
|
||||
X(IS_SMALLER, __is_greater) \
|
||||
X(IS_SMALLER_OR_EQUAL, __is_greater_or_equal)
|
||||
|
||||
#define X(op, meth) static zend_string *s_##meth;
|
||||
ALL_OPS(X)
|
||||
GREATER_OPS(X)
|
||||
#undef X
|
||||
|
||||
/* {{{ operator_method_name */
|
||||
@@ -96,13 +104,13 @@ ALL_OPS(X)
|
||||
/* }}} */
|
||||
|
||||
/* {{{ operator_get_method */
|
||||
static zend_bool operator_get_method(zend_uchar opcode, zval *obj,
|
||||
static zend_bool operator_get_method(zend_string *method, zval *obj,
|
||||
zend_fcall_info *fci,
|
||||
zend_fcall_info_cache *fcc) {
|
||||
memset(fci, 0, sizeof(zend_fcall_info));
|
||||
fci->size = sizeof(zend_fcall_info);
|
||||
fci->object = Z_OBJ_P(obj);
|
||||
ZVAL_STR(&(fci->function_name), operator_method_name(opcode));
|
||||
ZVAL_STR(&(fci->function_name), method);
|
||||
|
||||
if (!zend_is_callable_ex(&(fci->function_name), fci->object,
|
||||
IS_CALLABLE_CHECK_SILENT | IS_CALLABLE_STRICT,
|
||||
@@ -122,13 +130,28 @@ static zend_bool operator_get_method(zend_uchar opcode, zval *obj,
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ operator_is_greater_op */
|
||||
static inline zend_bool operator_is_greater_op(const zend_op *opline, zend_string **pmethod) {
|
||||
if (opline->extended_value == 1) {
|
||||
switch (opline->opcode) {
|
||||
#define X(op, meth) \
|
||||
case ZEND_##op: *pmethod = s_##meth; return 1;
|
||||
GREATER_OPS(X)
|
||||
#undef X
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ op_handler */
|
||||
static int op_handler(zend_execute_data *execute_data) {
|
||||
USE_OPLINE
|
||||
zend_free_op free_op1 = NULL, free_op2 = NULL;
|
||||
zval *op1, *op2;
|
||||
zval *op1, *op2 = NULL;
|
||||
zend_fcall_info fci;
|
||||
zend_fcall_info_cache fcc;
|
||||
zend_string *method = operator_method_name(opline->opcode);
|
||||
|
||||
if (opline->op1_type == IS_UNUSED) {
|
||||
/* Assign op */
|
||||
@@ -137,23 +160,32 @@ static int op_handler(zend_execute_data *execute_data) {
|
||||
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
|
||||
}
|
||||
ZVAL_DEREF(op1);
|
||||
if ((Z_TYPE_P(op1) != IS_OBJECT) ||
|
||||
!operator_get_method(opline->opcode, op1, &fci, &fcc)) {
|
||||
/* Not an overloaded call */
|
||||
return ZEND_USER_OPCODE_DISPATCH;
|
||||
}
|
||||
|
||||
fci.retval = EX_VAR(opline->result.var);
|
||||
switch (opline->opcode) {
|
||||
#define X(op, meth) \
|
||||
case ZEND_##op:
|
||||
BINARY_OPS(X)
|
||||
BINARY_ASSIGN_OPS(X)
|
||||
#undef X
|
||||
fci.params = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
|
||||
fci.param_count = 1;
|
||||
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
|
||||
}
|
||||
|
||||
if (operator_is_greater_op(opline, &method)) {
|
||||
zval *tmp = op1;
|
||||
zend_free_op free_tmp = free_op1;
|
||||
op1 = op2; op2 = tmp;
|
||||
free_op1 = free_op2; free_op2 = free_tmp;
|
||||
}
|
||||
|
||||
if ((Z_TYPE_P(op1) != IS_OBJECT) ||
|
||||
!operator_get_method(method, op1, &fci, &fcc)) {
|
||||
/* Not an overloaded call */
|
||||
return ZEND_USER_OPCODE_DISPATCH;
|
||||
}
|
||||
|
||||
fci.retval = EX_VAR(opline->result.var);
|
||||
fci.params = op2;
|
||||
fci.param_count = op2 ? 1 : 0;
|
||||
if (FAILURE == zend_call_function(&fci, &fcc)) {
|
||||
php_error(E_WARNING, "Failed calling %s::%s()", Z_OBJCE_P(op1)->name, Z_STRVAL(fci.function_name));
|
||||
ZVAL_NULL(fci.retval);
|
||||
@@ -168,6 +200,11 @@ BINARY_ASSIGN_OPS(X)
|
||||
|
||||
/* {{{ MINIT */
|
||||
static PHP_MINIT_FUNCTION(operator) {
|
||||
#define X(op, meth) \
|
||||
s_##meth = zend_string_init(#meth, strlen(#meth), 1);
|
||||
GREATER_OPS(X)
|
||||
#undef X
|
||||
|
||||
#define X(op, meth) \
|
||||
s_##meth = zend_string_init(#meth, strlen(#meth), 1); \
|
||||
zend_set_user_opcode_handler(ZEND_##op, op_handler);
|
||||
|
||||
@@ -30,7 +30,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
|
||||
<license uri="http://www.php.net/license">PHP</license>
|
||||
<notes>
|
||||
* Rewrote for PHP7, dropped PHP5 support
|
||||
* Removed is_greater(_or_equal) support
|
||||
* Removed pre/post inc/dec support for objects in object properties (this will come back eventually)
|
||||
* Added pow, assign-pow, and spaceship operators
|
||||
</notes>
|
||||
|
||||
13
php7-is_greater.diff
Normal file
13
php7-is_greater.diff
Normal file
@@ -0,0 +1,13 @@
|
||||
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
|
||||
index 88d7192..b797939 100644
|
||||
--- a/Zend/zend_compile.c
|
||||
+++ b/Zend/zend_compile.c
|
||||
@@ -6716,7 +6716,7 @@ void zend_compile_greater(znode *result, zend_ast *ast) /* {{{ */
|
||||
|
||||
zend_emit_op_tmp(result,
|
||||
ast->kind == ZEND_AST_GREATER ? ZEND_IS_SMALLER : ZEND_IS_SMALLER_OR_EQUAL,
|
||||
- &right_node, &left_node);
|
||||
+ &right_node, &left_node)->extended_value = 1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
28
tests/compare2.phpt
Normal file
28
tests/compare2.phpt
Normal file
@@ -0,0 +1,28 @@
|
||||
--TEST--
|
||||
Extended comparison ops
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("operator")) print "skip";
|
||||
--FILE--
|
||||
<?php
|
||||
class foo {
|
||||
private $value;
|
||||
function __is_greater($val) {
|
||||
return $this->value > $val;
|
||||
}
|
||||
function __is_greater_or_equal($val) {
|
||||
return $this->value >= $val;
|
||||
}
|
||||
function __construct($init) {
|
||||
$this->value = $init;
|
||||
}
|
||||
}
|
||||
$c = new foo(5);
|
||||
var_dump($c > 5);
|
||||
var_dump($c > 4);
|
||||
var_dump($c >= 5);
|
||||
var_dump($c >= 6);
|
||||
--EXPECT--
|
||||
bool(false)
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(false)
|
||||
Reference in New Issue
Block a user