diff --git a/.gitignore b/.gitignore index 9cd0bc0..9f5fa5c 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ /config.status /config.sub /configure +/configure.ac /configure.in /install-sh /libtool diff --git a/README.md b/README.md new file mode 100644 index 0000000..ca830fa --- /dev/null +++ b/README.md @@ -0,0 +1,66 @@ +# Operator overloading extension for PHP7 + +## Usage + +Implement magic methods in a class to provide operator overloading automatically, for example: + +```php +class C { + private $value = 0; + public function __add($delta) { + $this->value += $delta; + return $this; + } + + public function __toString() { + return strval($this->value); + } +} + +$c = new C; +var_dump($c + 5); // object(C)#1 { ["C:value:private"]=>5 } +``` + +The following overload methods are supported: + +| Operator | Method | +|:---:| --- | +| $o + $arg | `__add($arg)` | +| $o - $arg | `__sub($arg)` | +| $o * $arg | `__mul($arg)` | +| $o / $arg | `__div($arg)` | +| $o % $arg | `__mod($arg)` | +| $o ** $arg | `__pow($arg)` | +| $o << $arg | `__sl($arg)` | +| $o >> $arg | `__sr($arg)` | +| $o . $arg | `__concat($arg)` | +| $o | $arg | `__bw_or($arg)` | +| $o & $arg | `__bw_and($arg)` | +| $o ^ $arg | `__bw_xor($arg)` | +| ~$o | `__bw_not()` | +| $o === $arg | `__is_identical($arg)` | +| $o !== $arg | `__is_not_identical($arg)` | +| $o == $arg | `__is_equal($arg)` | +| $o != $arg | `__is_not_equal($arg)` | +| $o < $arg | `__is_smaller($arg)` | +| $o <= $arg | `__is_smaller_or_equal)($arg)` | +| $o <=> $arg | `__cmp($arg)` | +| ++$o | `__pre_inc()` | +| $o++ | `__post_inc()` | +| --$o | `__pre_dec()` | +| $o-- | `__post_dec()` | +| $o = $arg | `__assign($arg)` | +| $o += $arg | `__assign_add($arg)` | +| $o -= $arg | `__assign_sub($arg)` | +| $o *= $arg | `__assign_mul($arg)` | +| $o /= $arg | `__assign_div($arg)` | +| $o %= $arg | `__assign_mod($arg)` | +| $o **= $arg | `__assign_pow($arg)` | +| $o <<= $arg | `__assign_sl($arg)` | +| $o >>= $arg | `__assign_sr($arg)` | +| $o .= $arg | `__assign_concat($arg)` | +| $o |= $arg | `__assign_bw_or($arg)` | +| $o &= $arg | `__assign_bw_and($arg)` | +| $o ^= $arg | `__assign_bw_xor($arg)` | + + diff --git a/compare-greater-5.0.5.diff b/compare-greater-5.0.5.diff deleted file mode 100644 index f6a347e..0000000 --- a/compare-greater-5.0.5.diff +++ /dev/null @@ -1,66 +0,0 @@ -Index: Zend/zend_compile.c -=================================================================== -RCS file: /repository/ZendEngine2/zend_compile.c,v -retrieving revision 1.567.2.33 -diff -u -r1.567.2.33 zend_compile.c ---- Zend/zend_compile.c 24 Nov 2005 11:33:27 -0000 1.567.2.33 -+++ Zend/zend_compile.c 8 Feb 2006 21:05:21 -0000 -@@ -235,6 +235,20 @@ - } - - -+void zend_do_binary_compare_op(zend_uchar op, znode *result, znode *op1, znode *op2, zend_uint extval TSRMLS_DC) -+{ -+ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); -+ -+ opline->opcode = op; -+ opline->result.op_type = IS_TMP_VAR; -+ opline->result.u.var = get_temporary_variable(CG(active_op_array)); -+ opline->op1 = *op1; -+ opline->op2 = *op2; -+ opline->extended_value = extval; -+ *result = opline->result; -+} -+ -+ - void zend_do_unary_op(zend_uchar op, znode *result, znode *op1 TSRMLS_DC) - { - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); -Index: Zend/zend_compile.h -=================================================================== -RCS file: /repository/ZendEngine2/zend_compile.h,v -retrieving revision 1.284.2.7 -diff -u -r1.284.2.7 zend_compile.h ---- Zend/zend_compile.h 20 Sep 2005 11:38:37 -0000 1.284.2.7 -+++ Zend/zend_compile.h 8 Feb 2006 21:05:21 -0000 -@@ -321,6 +321,8 @@ - - - /* parser-driven code generators */ -+#define ZEND_HAVE_DO_BINARY_COMPARE_OP 1 -+void zend_do_binary_compare_op(zend_uchar op, znode *result, znode *op1, znode *op2, zend_uint extval TSRMLS_DC); - void zend_do_binary_op(zend_uchar op, znode *result, znode *op1, znode *op2 TSRMLS_DC); - void zend_do_unary_op(zend_uchar op, znode *result, znode *op1 TSRMLS_DC); - void zend_do_binary_assign_op(zend_uchar op, znode *result, znode *op1, znode *op2 TSRMLS_DC); -Index: Zend/zend_language_parser.y -=================================================================== -RCS file: /repository/ZendEngine2/zend_language_parser.y,v -retrieving revision 1.144.2.4 -diff -u -r1.144.2.4 zend_language_parser.y ---- Zend/zend_language_parser.y 21 Sep 2005 09:58:10 -0000 1.144.2.4 -+++ Zend/zend_language_parser.y 8 Feb 2006 21:05:21 -0000 -@@ -585,10 +585,10 @@ - | expr T_IS_NOT_IDENTICAL expr { zend_do_binary_op(ZEND_IS_NOT_IDENTICAL, &$$, &$1, &$3 TSRMLS_CC); } - | expr T_IS_EQUAL expr { zend_do_binary_op(ZEND_IS_EQUAL, &$$, &$1, &$3 TSRMLS_CC); } - | expr T_IS_NOT_EQUAL expr { zend_do_binary_op(ZEND_IS_NOT_EQUAL, &$$, &$1, &$3 TSRMLS_CC); } -- | expr '<' expr { zend_do_binary_op(ZEND_IS_SMALLER, &$$, &$1, &$3 TSRMLS_CC); } -- | expr T_IS_SMALLER_OR_EQUAL expr { zend_do_binary_op(ZEND_IS_SMALLER_OR_EQUAL, &$$, &$1, &$3 TSRMLS_CC); } -- | expr '>' expr { zend_do_binary_op(ZEND_IS_SMALLER, &$$, &$3, &$1 TSRMLS_CC); } -- | expr T_IS_GREATER_OR_EQUAL expr { zend_do_binary_op(ZEND_IS_SMALLER_OR_EQUAL, &$$, &$3, &$1 TSRMLS_CC); } -+ | expr '<' expr { zend_do_binary_compare_op(ZEND_IS_SMALLER, &$$, &$1, &$3, 0 TSRMLS_CC); } -+ | expr T_IS_SMALLER_OR_EQUAL expr { zend_do_binary_compare_op(ZEND_IS_SMALLER_OR_EQUAL, &$$, &$1, &$3, 0 TSRMLS_CC); } -+ | expr '>' expr { zend_do_binary_compare_op(ZEND_IS_SMALLER, &$$, &$3, &$1, 1 TSRMLS_CC); } -+ | expr T_IS_GREATER_OR_EQUAL expr { zend_do_binary_compare_op(ZEND_IS_SMALLER_OR_EQUAL, &$$, &$3, &$1, 1 TSRMLS_CC); } - | expr T_INSTANCEOF class_name_reference { zend_do_instanceof(&$$, &$1, &$3, 0 TSRMLS_CC); } - | '(' expr ')' { $$ = $2; } - | expr '?' { zend_do_begin_qm_op(&$1, &$2 TSRMLS_CC); } diff --git a/compare-greater-5.1.2.diff b/compare-greater-5.1.2.diff deleted file mode 100644 index 3ab1741..0000000 --- a/compare-greater-5.1.2.diff +++ /dev/null @@ -1,66 +0,0 @@ -Index: Zend/zend_compile.c -=================================================================== -RCS file: /repository/ZendEngine2/zend_compile.c,v -retrieving revision 1.647.2.21 -diff -u -r1.647.2.21 zend_compile.c ---- Zend/zend_compile.c 4 Jan 2006 23:53:04 -0000 1.647.2.21 -+++ Zend/zend_compile.c 8 Feb 2006 21:06:49 -0000 -@@ -267,6 +267,20 @@ - } - - -+void zend_do_binary_compare_op(zend_uchar op, znode *result, znode *op1, znode *op2, zend_uint extval TSRMLS_DC) -+{ -+ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); -+ -+ opline->opcode = op; -+ opline->result.op_type = IS_TMP_VAR; -+ opline->result.u.var = get_temporary_variable(CG(active_op_array)); -+ opline->op1 = *op1; -+ opline->op2 = *op2; -+ opline->extended_value = extval; -+ *result = opline->result; -+} -+ -+ - void zend_do_unary_op(zend_uchar op, znode *result, znode *op1 TSRMLS_DC) - { - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); -Index: Zend/zend_compile.h -=================================================================== -RCS file: /repository/ZendEngine2/zend_compile.h,v -retrieving revision 1.316.2.6 -diff -u -r1.316.2.6 zend_compile.h ---- Zend/zend_compile.h 4 Jan 2006 23:53:04 -0000 1.316.2.6 -+++ Zend/zend_compile.h 8 Feb 2006 21:06:49 -0000 -@@ -336,6 +336,8 @@ - - - /* parser-driven code generators */ -+#define ZEND_HAVE_DO_BINARY_COMPARE_OP 1 -+void zend_do_binary_compare_op(zend_uchar op, znode *result, znode *op1, znode *op2, zend_uint extval TSRMLS_DC); - void zend_do_binary_op(zend_uchar op, znode *result, znode *op1, znode *op2 TSRMLS_DC); - void zend_do_unary_op(zend_uchar op, znode *result, znode *op1 TSRMLS_DC); - void zend_do_binary_assign_op(zend_uchar op, znode *result, znode *op1, znode *op2 TSRMLS_DC); -Index: Zend/zend_language_parser.y -=================================================================== -RCS file: /repository/ZendEngine2/zend_language_parser.y,v -retrieving revision 1.160.2.3 -diff -u -r1.160.2.3 zend_language_parser.y ---- Zend/zend_language_parser.y 4 Jan 2006 23:53:04 -0000 1.160.2.3 -+++ Zend/zend_language_parser.y 8 Feb 2006 21:06:49 -0000 -@@ -597,10 +597,10 @@ - | expr T_IS_NOT_IDENTICAL expr { zend_do_binary_op(ZEND_IS_NOT_IDENTICAL, &$$, &$1, &$3 TSRMLS_CC); } - | expr T_IS_EQUAL expr { zend_do_binary_op(ZEND_IS_EQUAL, &$$, &$1, &$3 TSRMLS_CC); } - | expr T_IS_NOT_EQUAL expr { zend_do_binary_op(ZEND_IS_NOT_EQUAL, &$$, &$1, &$3 TSRMLS_CC); } -- | expr '<' expr { zend_do_binary_op(ZEND_IS_SMALLER, &$$, &$1, &$3 TSRMLS_CC); } -- | expr T_IS_SMALLER_OR_EQUAL expr { zend_do_binary_op(ZEND_IS_SMALLER_OR_EQUAL, &$$, &$1, &$3 TSRMLS_CC); } -- | expr '>' expr { zend_do_binary_op(ZEND_IS_SMALLER, &$$, &$3, &$1 TSRMLS_CC); } -- | expr T_IS_GREATER_OR_EQUAL expr { zend_do_binary_op(ZEND_IS_SMALLER_OR_EQUAL, &$$, &$3, &$1 TSRMLS_CC); } -+ | expr '<' expr { zend_do_binary_compare_op(ZEND_IS_SMALLER, &$$, &$1, &$3, 0 TSRMLS_CC); } -+ | expr T_IS_SMALLER_OR_EQUAL expr { zend_do_binary_compare_op(ZEND_IS_SMALLER_OR_EQUAL, &$$, &$1, &$3, 0 TSRMLS_CC); } -+ | expr '>' expr { zend_do_binary_compare_op(ZEND_IS_SMALLER, &$$, &$3, &$1, 1 TSRMLS_CC); } -+ | expr T_IS_GREATER_OR_EQUAL expr { zend_do_binary_compare_op(ZEND_IS_SMALLER_OR_EQUAL, &$$, &$3, &$1, 1 TSRMLS_CC); } - | expr T_INSTANCEOF class_name_reference { zend_do_instanceof(&$$, &$1, &$3, 0 TSRMLS_CC); } - | '(' expr ')' { $$ = $2; } - | expr '?' { zend_do_begin_qm_op(&$1, &$2 TSRMLS_CC); } diff --git a/operator.c b/operator.c index d3af1af..4ba6ee0 100644 --- a/operator.c +++ b/operator.c @@ -1,616 +1,198 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 5 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2006 The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.0 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_0.txt. | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Author: Sara Golemon | - +----------------------------------------------------------------------+ -*/ - -/* $Id$ */ - #ifdef HAVE_CONFIG_H -#include "config.h" +# include "config.h" #endif #include "php.h" -#include "php_ini.h" -#include "ext/standard/info.h" -#include "php_operator.h" -#ifndef ZEND_VM_KIND_CALL -/* ZEND_VM_KIND gets defined to this, but this doesn't get defined... go figure... */ -#define ZEND_VM_KIND_CALL 1 -#endif +#define USE_OPLINE const zend_op *opline = EX(opline); +#define GET_OP1_ZVAL_PTR_UNDEF(fetch) \ + get_zval_ptr_undef(opline->op1_type, opline->op1, &free_op1, execute_data) +#define GET_OP2_ZVAL_PTR_UNDEF(fetch) \ + get_zval_ptr_undef(opline->op2_type, opline->op2, &free_op2, execute_data) -#if defined(ZEND_ENGINE_2_1) && ZEND_VM_KIND != ZEND_VM_KIND_CALL -# error "Operator overload support requires CALL style Zend VM" -#endif +#define FREE_OP1 if (free_op1) { zval_ptr_dtor_nogc(free_op1); } +#define FREE_OP2 if (free_op2) { zval_ptr_dtor_nogc(free_op2); } -/* *********** - * Helpers * - *********** */ - -#ifndef EX_TMP_VAR -# define EX_TMP_VAR(ex, ofs) ((temp_variable *)((char*)(ex)->Ts + (ofs))) -#endif - -static inline int php_operator_method(zval *result, zval *op1, const char *method, int method_len, zval *op2 TSRMLS_DC) -{ - zval *caller; - int ret; - - ALLOC_INIT_ZVAL(caller); - array_init(caller); - - Z_ADDREF_P(op1); - add_index_zval(caller, 0, op1); - add_index_stringl(caller, 1, (char*)method, method_len, 1); - - ret = call_user_function(EG(function_table), NULL, caller, result, op2 ? 1 : 0, op2 ? &op2 : NULL TSRMLS_CC); - zval_ptr_dtor(&caller); - - return ret; +static +zval *get_zval_ptr_undef(zend_uchar op_type, znode_op op, zend_free_op *free_op, + zend_execute_data *execute_data) { + switch (op_type) { + case IS_TMP_VAR: + case IS_VAR: return (*free_op = EX_VAR(op.var)); + case IS_CONST: return EX_CONSTANT(op); + case IS_CV: return EX_VAR(op.var); + default: return NULL; + } } -#ifdef ZEND_ENGINE_2_4 -typedef znode_op operator_znode_op; -#else -typedef znode operator_znode_op; -#endif +/* ----------------------------------------------------------------------- */ -static inline zval *php_operator_zval_ptr(zend_uchar optype, operator_znode_op *node_op, zend_free_op *should_free, zend_execute_data *execute_data, zend_bool silent TSRMLS_DC) -{ - should_free->var = NULL; +#define UNARY_OPS(X) \ + X(BW_NOT, __bw_not) - switch (optype) { - case IS_CONST: -#ifdef ZEND_ENGINE_2_4 - return &node_op->literal->constant; -#else - return &(node_op->u.constant); -#endif - case IS_VAR: - return EX_TMP_VAR(execute_data, PHP_OPERATOR_OP_U(*node_op).var)->var.ptr; - case IS_TMP_VAR: - return (should_free->var = &EX_TMP_VAR(execute_data, PHP_OPERATOR_OP_U(*node_op).var)->tmp_var); -#ifdef ZEND_ENGINE_2_1 - case IS_CV: - { - zval ***ret = EX_CV_NUM(execute_data, PHP_OPERATOR_OP_U(*node_op).var); +#define BINARY_OPS(X) \ + X(ADD, __add) \ + X(SUB, __sub) \ + X(MUL, __mul) \ + X(DIV, __div) \ + X(MOD, __mod) \ + X(POW, __pow) \ + X(SL, __sl) \ + X(SR, __sr) \ + X(CONCAT, __concat) \ + X(BW_OR, __bw_or) \ + X(BW_AND, __bw_and) \ + X(BW_XOR, __bw_xor) \ + X(IS_IDENTICAL, __is_identical) \ + X(IS_NOT_IDENTICAL, __is_not_identical) \ + X(IS_EQUAL, __is_equal) \ + X(IS_NOT_EQUAL, __is_not_equal) \ + X(IS_SMALLER, __is_smaller) \ + X(IS_SMALLER_OR_EQUAL, __is_smaller_or_equal) \ + X(SPACESHIP, __cmp) - if (!*ret) { - zend_compiled_variable *cv = &EG(active_op_array)->vars[PHP_OPERATOR_OP_U(*node_op).var]; - if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ret)==FAILURE) { - if (!silent) { - zend_error(E_NOTICE, "Undefined variable: %s", cv->name); - } - return &EG(uninitialized_zval); - } - } - return **ret; - } -#endif - case IS_UNUSED: - default: - return NULL; - } +#define UNARY_ASSIGN_OPS(X) \ + X(PRE_INC, __pre_inc) \ + X(POST_INC, __post_inc) \ + X(PRE_DEC, __pre_dec) \ + X(POST_DEC, __post_dec) + +#define BINARY_ASSIGN_OPS(X) \ + X(ASSIGN, __assign) \ + X(ASSIGN_ADD, __assign_add) \ + X(ASSIGN_SUB, __assign_sub) \ + X(ASSIGN_MUL, __assign_mul) \ + X(ASSIGN_DIV, __assign_div) \ + X(ASSIGN_MOD, __assign_mod) \ + X(ASSIGN_POW, __assign_pow) \ + X(ASSIGN_SL, __assign_sl) \ + X(ASSIGN_SR, __assign_sr) \ + X(ASSIGN_CONCAT, __assign_concat) \ + X(ASSIGN_BW_OR, __assign_bw_or) \ + X(ASSIGN_BW_AND, __assign_bw_and) \ + X(ASSIGN_BW_XOR, __assign_bw_xor) + +#define ALL_OPS(X) \ + UNARY_OPS(X) \ + BINARY_OPS(X) \ + UNARY_ASSIGN_OPS(X) \ + BINARY_ASSIGN_OPS(X) + +#define X(op, meth) static zend_string *s_##meth; +ALL_OPS(X) +#undef X + +/* {{{ operator_method_name */ +static inline zend_string* operator_method_name(zend_uchar opcode) { + switch (opcode) { +#define X(op, meth) case ZEND_##op: return s_##meth; +ALL_OPS(X) +#undef X + default: + ZEND_ASSERT(0); + return NULL; + } } +/* }}} */ -static inline zval **php_operator_zval_ptr_ptr(zend_uchar optype, operator_znode_op *node_op, zend_execute_data *execute_data, zend_bool silent TSRMLS_DC) -{ - switch (optype) { - case IS_VAR: - return EX_TMP_VAR(execute_data, PHP_OPERATOR_OP_U(*node_op).var)->var.ptr_ptr; -#ifdef ZEND_ENGINE_2_1 - case IS_CV: - { - zval ***ret = EX_CV_NUM(execute_data, PHP_OPERATOR_OP_U(*node_op).var); +/* {{{ operator_get_method */ +static zend_bool operator_get_method(zend_uchar opcode, 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)); - if (!*ret) { - zend_compiled_variable *cv = &EG(active_op_array)->vars[PHP_OPERATOR_OP_U(*node_op).var]; - if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ret)==FAILURE) { - if (!silent) { - zend_error(E_NOTICE, "Undefined variable: %s", cv->name); - } - return &EG(uninitialized_zval_ptr); - } - } - return *ret; - } -#endif - case IS_CONST: - case IS_TMP_VAR: - case IS_UNUSED: - default: - return NULL; - } + if (!zend_is_callable_ex(&(fci->function_name), fci->object, + IS_CALLABLE_CHECK_SILENT | IS_CALLABLE_STRICT, + NULL, fcc, NULL)) { + return 0; + } + /* Disallow dispatch via __call */ + if (fcc->function_handler == Z_OBJCE_P(obj)->__call) { return 0; } + if (fcc->function_handler->type == ZEND_USER_FUNCTION) { + zend_op_array *oparray = (zend_op_array*)(fcc->function_handler); + if (oparray->fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) { + return 0; + } + } + + return 1; } +/* }}} */ -static inline zval *php_operator_get_result_ptr(zend_op *opline, zend_execute_data *execute_data) -{ - zval *tmp; +/* {{{ 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; + zend_fcall_info fci; + zend_fcall_info_cache fcc; - if (PHP_OPERATOR_OP_TYPE(opline->result) == IS_TMP_VAR) { - return &EX_TMP_VAR(execute_data, PHP_OPERATOR_OP_U(opline->result).var)->tmp_var; - } + if (opline->op1_type == IS_UNUSED) { + /* Assign op */ + op1 = EX_VAR(opline->result.var); + } else { + 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; + } - ALLOC_INIT_ZVAL(tmp); - return tmp; + 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; + } + + 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); + } + + FREE_OP2 + FREE_OP1 + EX(opline) = opline + 1; + return ZEND_USER_OPCODE_CONTINUE; } +/* }}} */ -static inline void php_operator_set_result_ptr(zval *result, zend_op *opline, zend_execute_data *execute_data) -{ - switch (PHP_OPERATOR_OP_TYPE(opline->result)) { - case IS_TMP_VAR: - /* Nothing to do */ - return; - case IS_VAR: - EX_TMP_VAR(execute_data, PHP_OPERATOR_OP_U(opline->result).var)->var.ptr = result; - EX_TMP_VAR(execute_data, PHP_OPERATOR_OP_U(opline->result).var)->var.ptr_ptr = - &EX_TMP_VAR(execute_data, PHP_OPERATOR_OP_U(opline->result).var)->var.ptr; - return; - default: - zval_ptr_dtor(&result); - } +/* {{{ MINIT */ +static PHP_MINIT_FUNCTION(operator) { +#define X(op, meth) \ + s_##meth = zend_string_init(#meth, strlen(#meth), 1); \ + zend_set_user_opcode_handler(ZEND_##op, op_handler); +ALL_OPS(X) +#undef X + + return SUCCESS; } +/* }}} */ -#ifdef ZEND_ENGINE_2_1 -static inline int _php_operator_decode(zend_op *opline) -{ - int ret = opline->opcode * 25; - switch (PHP_OPERATOR_OP_TYPE(opline->op1)) { - case IS_CONST: break; - case IS_TMP_VAR: ret += 5; break; - case IS_VAR: ret += 10; break; - case IS_UNUSED: ret += 15; break; - case IS_CV: ret += 20; break; - } - switch (PHP_OPERATOR_OP_TYPE(opline->op2)) { - case IS_CONST: break; - case IS_TMP_VAR: ret += 1; break; - case IS_VAR: ret += 2; break; - case IS_UNUSED: ret += 3; break; - case IS_CV: ret += 4; break; - } - return ret; -} - -#if defined(ZEND_ENGINE_2_5) -# define PHP_OPERATOR_OPCODE_COUNT 163 -#elif defined(ZEND_ENGINE_2_4) -# define PHP_OPERATOR_OPCODE_COUNT 158 -#elif defined(ZEND_ENGINE_2_3) -# define PHP_OPERATOR_OPCODE_COUNT 153 -#else /* PHP 5.1 and 5.2 */ -# define PHP_OPERATOR_OPCODE_COUNT 150 -#endif - -#define PHP_OPERATOR_OPHANDLER_COUNT ((25 * (PHP_OPERATOR_OPCODE_COUNT + 1)) + 1) -#define PHP_OPERATOR_REPLACE_OPCODE(opname) { int i; for(i = 5; i < 25; i++) if (php_operator_opcode_handlers[(opname*25) + i]) php_operator_opcode_handlers[(opname*25) + i] = php_operator_op_##opname; } -#define PHP_OPERATOR_REPLACE_ALL_OPCODE(opname) { int i; for(i = 0; i < 25; i++) if (php_operator_opcode_handlers[(opname*25) + i]) php_operator_opcode_handlers[(opname*25) + i] = php_operator_op_##opname; } -#define PHP_OPERATOR_DECODE(opline) _php_operator_decode(opline) -#define PHP_OPERATOR_GET_OPLINE zend_op *opline = (execute_data->opline); -#else -#define PHP_OPERATOR_OPCODE_COUNT 512 -#define PHP_OPERATOR_OPHANDLER_COUNT PHP_OPERATOR_OPCODE_COUNT -#define PHP_OPERATOR_REPLACE_OPCODE(opname) zend_opcode_handlers[opname] = php_operator_op_##opname -#define PHP_OPERATOR_REPLACE_ALL_OPCODE(opname) zend_opcode_handlers[opname] = php_operator_op_##opname -#define PHP_OPERATOR_DECODE(opline) (opline->opcode) -#define PHP_OPERATOR_GET_OPLINE -#endif - -static opcode_handler_t *php_operator_original_opcode_handlers; -static opcode_handler_t php_operator_opcode_handlers[PHP_OPERATOR_OPHANDLER_COUNT]; - -#ifndef ZEND_FASTCALL -#define ZEND_FASTCALL -#endif - -#ifndef Z_ADDREF_P -# define Z_ADDREF_P(pzv) ((pzv)->refcount++) -#endif - -/* ******************* - * Op Replacements * - ******************* */ - -#define PHP_OPERATOR_BINARY_OP(opname,methodname) static int ZEND_FASTCALL php_operator_op_##opname (ZEND_OPCODE_HANDLER_ARGS) { return _php_operator_binary_op(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU, methodname, sizeof(methodname) - 1); } -static inline int _php_operator_binary_op(ZEND_OPCODE_HANDLER_ARGS, const char *methodname, int methodname_len) -{ - PHP_OPERATOR_GET_OPLINE - zend_free_op free_op1, free_op2; - zval *result; - zval *op1 = php_operator_zval_ptr(PHP_OPERATOR_OP_TYPE(opline->op1), &(opline->op1), &free_op1, execute_data, (opline->opcode == ZEND_ASSIGN) TSRMLS_CC); - zval *op2 = php_operator_zval_ptr(PHP_OPERATOR_OP_TYPE(opline->op2), &(opline->op2), &free_op2, execute_data, 0 TSRMLS_CC); - -#ifdef ZEND_HAVE_DO_BINARY_COMPARE_OP - if (opline->extended_value && - opline->opcode == ZEND_IS_SMALLER) { - zval *swap = op1; op1 = op2; op2 = swap; - - methodname = "__is_greater"; - methodname_len = sizeof("__is_greater") - 1; - } else if (opline->extended_value && - opline->opcode == ZEND_IS_SMALLER_OR_EQUAL) { - zval *swap = op1; op1 = op2; op2 = swap; - - methodname = "__is_greater_or_equal"; - methodname_len = sizeof("__is_greater_or_equal") - 1; - } -#endif - - if (!op1 || op1->type != IS_OBJECT || - !zend_hash_exists(&Z_OBJCE_P(op1)->function_table, (char*)methodname, methodname_len + 1)) { - /* Rely on primary handler */ - return php_operator_original_opcode_handlers[PHP_OPERATOR_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - - result = php_operator_get_result_ptr(opline, execute_data); - if (php_operator_method(result, op1, methodname, methodname_len, op2 TSRMLS_CC) == FAILURE) { - /* Fallback on original handler */ - if (PHP_OPERATOR_OP_TYPE(opline->result) != IS_TMP_VAR) zval_ptr_dtor(&result); - return php_operator_original_opcode_handlers[PHP_OPERATOR_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - - php_operator_set_result_ptr(result, opline, execute_data); - if (free_op1.var) zval_dtor(free_op1.var); - if (free_op2.var) zval_dtor(free_op2.var); - execute_data->opline++; - return 0; -} - -#define PHP_OPERATOR_UNARY_OP(opname,methodname) static int ZEND_FASTCALL php_operator_op_##opname (ZEND_OPCODE_HANDLER_ARGS) { return _php_operator_unary_op(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU, methodname, sizeof(methodname) - 1); } -static inline int _php_operator_unary_op(ZEND_OPCODE_HANDLER_ARGS, const char *methodname, int methodname_len) -{ - PHP_OPERATOR_GET_OPLINE - zend_free_op free_op1; - zval *result; - zval *op1 = php_operator_zval_ptr(PHP_OPERATOR_OP_TYPE(opline->op1), &(opline->op1), &free_op1, execute_data, 0 TSRMLS_CC); - - if (!op1 || - op1->type != IS_OBJECT || - !zend_hash_exists(&Z_OBJCE_P(op1)->function_table, (char*)methodname, methodname_len + 1)) { - /* Rely on primary handler */ - return php_operator_original_opcode_handlers[PHP_OPERATOR_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - - result = php_operator_get_result_ptr(opline, execute_data); - if (php_operator_method(result, op1, methodname, methodname_len, NULL TSRMLS_CC) == FAILURE) { - /* Fallback on original handler */ - if (PHP_OPERATOR_OP_TYPE(opline->result) != IS_TMP_VAR) zval_ptr_dtor(&result); - return php_operator_original_opcode_handlers[PHP_OPERATOR_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - - php_operator_set_result_ptr(result, opline, execute_data); - if (free_op1.var) zval_dtor(free_op1.var); - execute_data->opline++; - return 0; -} - -#ifdef ZEND_ENGINE_2_5 -# define BP_VAR_RW_55_CC , BP_VAR_RW -#else -# define BP_VAR_RW_55_CC -#endif - -#define PHP_OPERATOR_BINARY_ASSIGN_OP(opname,methodname) static int ZEND_FASTCALL php_operator_op_##opname (ZEND_OPCODE_HANDLER_ARGS) { return _php_operator_binary_assign_op(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU, methodname, sizeof(methodname) - 1); } -static int _php_operator_binary_assign_op(ZEND_OPCODE_HANDLER_ARGS, const char *methodname, int methodname_len) -{ - PHP_OPERATOR_GET_OPLINE - zend_free_op free_value, free_prop, free_obj; - zval *var = NULL, *value, *result; - zend_bool increment_opline = 0; - - free_prop.var = free_obj.var = NULL; - switch (opline->extended_value) { - case ZEND_ASSIGN_OBJ: - case ZEND_ASSIGN_DIM: - { - zend_op *opdata = opline + 1; - zval *object = php_operator_zval_ptr(PHP_OPERATOR_OP_TYPE(opline->op1), &(opline->op1), &free_obj, execute_data, 0 TSRMLS_CC); - zval *prop = php_operator_zval_ptr(PHP_OPERATOR_OP_TYPE(opline->op2), &(opline->op2), &free_prop, execute_data, (opline->opcode == ZEND_ASSIGN) TSRMLS_CC); - - if (!object || Z_TYPE_P(object) != IS_OBJECT || !prop) { - /* Let orignal handler throw error */ - return php_operator_original_opcode_handlers[PHP_OPERATOR_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - - increment_opline = 1; - value = php_operator_zval_ptr(PHP_OPERATOR_OP_TYPE(opdata->op1), &(opdata->op1), &free_value, execute_data, 0 TSRMLS_CC); - if (!value) { - /* Shouldn't happen */ - return php_operator_original_opcode_handlers[PHP_OPERATOR_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - - /* Plan A */ - if (opline->extended_value == ZEND_ASSIGN_OBJ && - Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval **varpp = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, prop BP_VAR_RW_55_CC PHP_OPERATOR_LITERAL_NULL_CC TSRMLS_CC); - if (varpp) { - var = *varpp; - break; - } - } - - /* Plan B */ - if (opline->extended_value == ZEND_ASSIGN_OBJ && - Z_OBJ_HT_P(object)->read_property) { - var = Z_OBJ_HT_P(object)->read_property(object, prop, BP_VAR_RW PHP_OPERATOR_LITERAL_NULL_CC TSRMLS_CC); - } else if (opline->extended_value == ZEND_ASSIGN_DIM && - Z_OBJ_HT_P(object)->read_dimension) { - var = Z_OBJ_HT_P(object)->read_dimension(object, prop, BP_VAR_RW TSRMLS_CC); - } - - break; - } - default: - var = php_operator_zval_ptr(PHP_OPERATOR_OP_TYPE(opline->op1), &(opline->op1), &free_obj, execute_data, (opline->opcode == ZEND_ASSIGN) TSRMLS_CC); - value = php_operator_zval_ptr(PHP_OPERATOR_OP_TYPE(opline->op2), &(opline->op2), &free_value, execute_data, 0 TSRMLS_CC); - } - - if (!var || Z_TYPE_P(var) != IS_OBJECT || - !zend_hash_exists(&Z_OBJCE_P(var)->function_table, (char*)methodname, methodname_len + 1)) { - /* Rely on primary handler */ - return php_operator_original_opcode_handlers[PHP_OPERATOR_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - - result = php_operator_get_result_ptr(opline, execute_data); - if (php_operator_method(result, var, methodname, methodname_len, value TSRMLS_CC) == FAILURE) { - /* Fallback on original handler */ - if (PHP_OPERATOR_OP_TYPE(opline->result) != IS_TMP_VAR) zval_ptr_dtor(&result); - return php_operator_original_opcode_handlers[PHP_OPERATOR_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - - if (free_prop.var) zval_dtor(free_prop.var); - if (free_value.var) zval_dtor(free_value.var); - php_operator_set_result_ptr(result, opline, execute_data); - execute_data->opline += increment_opline ? 2 : 1; - return 0; -} - -#define PHP_OPERATOR_UNARY_ASSIGN_OP(opname,methodname) static int ZEND_FASTCALL php_operator_op_##opname (ZEND_OPCODE_HANDLER_ARGS) { return _php_operator_unary_assign_op(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU, methodname, sizeof(methodname) - 1); } -static inline int _php_operator_unary_assign_op(ZEND_OPCODE_HANDLER_ARGS, const char *methodname, int methodname_len) -{ - PHP_OPERATOR_GET_OPLINE - zval *result; - zval **op1 = php_operator_zval_ptr_ptr(PHP_OPERATOR_OP_TYPE(opline->op1), &(opline->op1), execute_data, 0 TSRMLS_CC); - - if (!op1 || Z_TYPE_PP(op1) != IS_OBJECT || - !zend_hash_exists(&Z_OBJCE_PP(op1)->function_table, (char*)methodname, methodname_len + 1)) { - /* Rely on primary handler */ - return php_operator_original_opcode_handlers[PHP_OPERATOR_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - - result = php_operator_get_result_ptr(opline, execute_data); - if (php_operator_method(result, *op1, methodname, methodname_len, NULL TSRMLS_CC) == FAILURE) { - /* Fallback on original handler */ - if (PHP_OPERATOR_OP_TYPE(opline->result) != IS_TMP_VAR) zval_ptr_dtor(&result); - return php_operator_original_opcode_handlers[PHP_OPERATOR_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - - php_operator_set_result_ptr(result, opline, execute_data); - execute_data->opline++; - return 0; -} - -#define PHP_OPERATOR_UNARY_ASSIGN_OBJ_OP(opname,methodname) static int ZEND_FASTCALL php_operator_op_##opname (ZEND_OPCODE_HANDLER_ARGS) { return _php_operator_unary_assign_obj_op(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU, methodname, sizeof(methodname) - 1); } -static inline int _php_operator_unary_assign_obj_op(ZEND_OPCODE_HANDLER_ARGS, const char *methodname, int methodname_len) -{ - PHP_OPERATOR_GET_OPLINE - zend_free_op free_obj, free_prop; - zval *result; - zval *obj = php_operator_zval_ptr(PHP_OPERATOR_OP_TYPE(opline->op1), &(opline->op1), &free_obj, execute_data, 0 TSRMLS_CC); - zval *prop = php_operator_zval_ptr(PHP_OPERATOR_OP_TYPE(opline->op2), &(opline->op2), &free_prop, execute_data, 0 TSRMLS_CC); - zval *var = NULL; - - if (!obj || Z_TYPE_P(obj) != IS_OBJECT || !prop) { - /* Rely on primary handler */ - return php_operator_original_opcode_handlers[PHP_OPERATOR_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - - if (Z_OBJ_HT_P(obj)->get_property_ptr_ptr) { - zval **varpp = Z_OBJ_HT_P(obj)->get_property_ptr_ptr(obj, prop BP_VAR_RW_55_CC PHP_OPERATOR_LITERAL_NULL_CC TSRMLS_CC); - if (varpp) { - var = *varpp; - } - } - if (!var && Z_OBJ_HT_P(obj)->read_property) { - var = Z_OBJ_HT_P(obj)->read_property(obj, prop, BP_VAR_RW PHP_OPERATOR_LITERAL_NULL_CC TSRMLS_CC); - } - - if (!var || Z_TYPE_P(var) != IS_OBJECT || - !zend_hash_exists(&Z_OBJCE_P(var)->function_table, (char*)methodname, methodname_len + 1)) { - /* Rely on primary handler */ - return php_operator_original_opcode_handlers[PHP_OPERATOR_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - - result = php_operator_get_result_ptr(opline, execute_data); - if (php_operator_method(result, var, methodname, methodname_len, NULL TSRMLS_CC) == FAILURE) { - /* Fallback on original handler */ - if (PHP_OPERATOR_OP_TYPE(opline->result) != IS_TMP_VAR) zval_ptr_dtor(&result); - return php_operator_original_opcode_handlers[PHP_OPERATOR_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } - - if (free_obj.var) { zval_dtor(free_obj.var); } - if (free_prop.var) { zval_dtor(free_prop.var); } - php_operator_set_result_ptr(result, opline, execute_data); - execute_data->opline++; - return 0; -} - -PHP_OPERATOR_BINARY_OP(ZEND_ADD, "__add") -PHP_OPERATOR_BINARY_OP(ZEND_SUB, "__sub") -PHP_OPERATOR_BINARY_OP(ZEND_MUL, "__mul") -PHP_OPERATOR_BINARY_OP(ZEND_DIV, "__div") -PHP_OPERATOR_BINARY_OP(ZEND_MOD, "__mod") -PHP_OPERATOR_BINARY_OP(ZEND_SL, "__sl") -PHP_OPERATOR_BINARY_OP(ZEND_SR, "__sr") -PHP_OPERATOR_BINARY_OP(ZEND_CONCAT, "__concat") -PHP_OPERATOR_BINARY_OP(ZEND_BW_OR, "__bw_or") -PHP_OPERATOR_BINARY_OP(ZEND_BW_AND, "__bw_and") -PHP_OPERATOR_BINARY_OP(ZEND_BW_XOR, "__bw_xor") - -PHP_OPERATOR_BINARY_OP(ZEND_IS_IDENTICAL, "__is_identical") -PHP_OPERATOR_BINARY_OP(ZEND_IS_NOT_IDENTICAL, "__is_not_identical") -PHP_OPERATOR_BINARY_OP(ZEND_IS_EQUAL, "__is_equal") -PHP_OPERATOR_BINARY_OP(ZEND_IS_NOT_EQUAL, "__is_not_equal") - -PHP_OPERATOR_BINARY_OP(ZEND_IS_SMALLER, "__is_smaller") /* includes __is_greater when patch applied */ -PHP_OPERATOR_BINARY_OP(ZEND_IS_SMALLER_OR_EQUAL, "__is_smaller_or_equal") /* includes __is_greater_or_equal ... */ - -PHP_OPERATOR_UNARY_OP(ZEND_BW_NOT, "__bw_not") - -PHP_OPERATOR_BINARY_ASSIGN_OP(ZEND_ASSIGN, "__assign") -PHP_OPERATOR_BINARY_ASSIGN_OP(ZEND_ASSIGN_ADD, "__assign_add") -PHP_OPERATOR_BINARY_ASSIGN_OP(ZEND_ASSIGN_SUB, "__assign_sub") -PHP_OPERATOR_BINARY_ASSIGN_OP(ZEND_ASSIGN_MUL, "__assign_mul") -PHP_OPERATOR_BINARY_ASSIGN_OP(ZEND_ASSIGN_DIV, "__assign_div") -PHP_OPERATOR_BINARY_ASSIGN_OP(ZEND_ASSIGN_MOD, "__assign_mod") -PHP_OPERATOR_BINARY_ASSIGN_OP(ZEND_ASSIGN_SL, "__assign_sl") -PHP_OPERATOR_BINARY_ASSIGN_OP(ZEND_ASSIGN_SR, "__assign_sr") -PHP_OPERATOR_BINARY_ASSIGN_OP(ZEND_ASSIGN_CONCAT, "__assign_concat") -PHP_OPERATOR_BINARY_ASSIGN_OP(ZEND_ASSIGN_BW_OR, "__assign_bw_or") -PHP_OPERATOR_BINARY_ASSIGN_OP(ZEND_ASSIGN_BW_AND, "__assign_bw_and") -PHP_OPERATOR_BINARY_ASSIGN_OP(ZEND_ASSIGN_BW_XOR, "__assign_bw_xor") - -PHP_OPERATOR_UNARY_ASSIGN_OP(ZEND_PRE_INC, "__pre_inc") -PHP_OPERATOR_UNARY_ASSIGN_OP(ZEND_PRE_DEC, "__pre_dec") -PHP_OPERATOR_UNARY_ASSIGN_OP(ZEND_POST_INC, "__post_inc") -PHP_OPERATOR_UNARY_ASSIGN_OP(ZEND_POST_DEC, "__post_dec") - -PHP_OPERATOR_UNARY_ASSIGN_OBJ_OP(ZEND_PRE_INC_OBJ, "__pre_inc") -PHP_OPERATOR_UNARY_ASSIGN_OBJ_OP(ZEND_PRE_DEC_OBJ, "__pre_dec") -PHP_OPERATOR_UNARY_ASSIGN_OBJ_OP(ZEND_POST_INC_OBJ, "__post_inc") -PHP_OPERATOR_UNARY_ASSIGN_OBJ_OP(ZEND_POST_DEC_OBJ, "__post_dec") - -/* *********************** - * Module Housekeeping * - *********************** */ - -PHP_MINIT_FUNCTION(operator) -{ - memcpy(php_operator_opcode_handlers, zend_opcode_handlers, sizeof(php_operator_opcode_handlers)); - -#if PHP_MAJOR_VERSION > 5 || PHP_MINOR_VERSION > 0 - php_operator_original_opcode_handlers = zend_opcode_handlers; - zend_opcode_handlers = php_operator_opcode_handlers; -#else - php_operator_original_opcode_handlers = php_operator_opcode_handlers; -#endif - - /* Binaries */ - PHP_OPERATOR_REPLACE_OPCODE(ZEND_ADD); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_SUB); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_MUL); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_DIV); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_MOD); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_SL); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_SR); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_CONCAT); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_BW_OR); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_BW_AND); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_BW_XOR); - - /* Comparators (Binaries in disguise) */ - PHP_OPERATOR_REPLACE_OPCODE(ZEND_IS_IDENTICAL); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_IS_NOT_IDENTICAL); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_IS_EQUAL); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_IS_NOT_EQUAL); - -#ifdef ZEND_HAVE_DO_BINARY_COMPARE_OP -/* __is_greater and __is_greater_or_equal support requires patching parser: compare-greater-VERSION.diff */ - REGISTER_LONG_CONSTANT("OPERATOR_COMPARE_PATCH", 1, CONST_CS | CONST_PERSISTENT); - PHP_OPERATOR_REPLACE_ALL_OPCODE(ZEND_IS_SMALLER); - PHP_OPERATOR_REPLACE_ALL_OPCODE(ZEND_IS_SMALLER_OR_EQUAL); -#else - REGISTER_LONG_CONSTANT("OPERATOR_COMPARE_PATCH", 0, CONST_CS | CONST_PERSISTENT); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_IS_SMALLER); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_IS_SMALLER_OR_EQUAL); -#endif - - /* Unaries */ - PHP_OPERATOR_REPLACE_OPCODE(ZEND_BW_NOT); - - /* Binary Assign */ - PHP_OPERATOR_REPLACE_OPCODE(ZEND_ASSIGN); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_ASSIGN_ADD); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_ASSIGN_SUB); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_ASSIGN_MUL); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_ASSIGN_DIV); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_ASSIGN_MOD); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_ASSIGN_SL); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_ASSIGN_SR); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_ASSIGN_CONCAT); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_ASSIGN_BW_OR); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_ASSIGN_BW_AND); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_ASSIGN_BW_XOR); - - /* Unary Assign */ - PHP_OPERATOR_REPLACE_OPCODE(ZEND_PRE_INC); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_PRE_DEC); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_POST_INC); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_POST_DEC); - - /* Unary Assign Obj */ - PHP_OPERATOR_REPLACE_OPCODE(ZEND_PRE_INC_OBJ); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_PRE_DEC_OBJ); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_POST_INC_OBJ); - PHP_OPERATOR_REPLACE_OPCODE(ZEND_POST_DEC_OBJ); - - return SUCCESS; -} - - -PHP_MSHUTDOWN_FUNCTION(operator) -{ -#if PHP_MAJOR_VERSION > 5 || PHP_MINOR_VERSION > 0 - zend_opcode_handlers = php_operator_original_opcode_handlers; -#else - memcpy(zend_opcode_handlers, php_operator_original_opcode_handlers, sizeof(php_operator_opcode_handlers)); -#endif - - return SUCCESS; -} - -PHP_MINFO_FUNCTION(operator) -{ - php_info_print_table_start(); - php_info_print_table_header(2, "operator overloading support", "+ - * / % << >> . | & ^ ~ ! ++ -- " - "+= -= *= /= %= <<= >>= .= |= &= ^= ~= === !== == != < <= " -#ifdef ZEND_HAVE_DO_BINARY_COMPARE_OP - "> >= " -#endif - ); - php_info_print_table_row(2, "version", PHP_OPERATOR_VERSION); - php_info_print_table_end(); -} - -zend_module_entry operator_module_entry = { -#if ZEND_MODULE_API_NO >= 20010901 - STANDARD_MODULE_HEADER, -#endif - PHP_OPERATOR_EXTNAME, - NULL, - PHP_MINIT(operator), - PHP_MSHUTDOWN(operator), - NULL, /* RINIT */ - NULL, /* RSHUTDOWN */ - PHP_MINFO(operator), -#if ZEND_MODULE_API_NO >= 20010901 - PHP_OPERATOR_VERSION, -#endif - STANDARD_MODULE_PROPERTIES +/* {{{ operator_module_entry + */ +static zend_module_entry operator_module_entry = { + STANDARD_MODULE_HEADER, + "operator", + NULL, /* functions */ + PHP_MINIT(operator), + NULL, /* MSHUTDOWN */ + NULL, /* RINIT */ + NULL, /* RSHUTDOWN */ + NULL, /* MINFO */ + "7.2.0", + STANDARD_MODULE_PROPERTIES }; +/* }}} */ #ifdef COMPILE_DL_OPERATOR ZEND_GET_MODULE(operator) diff --git a/package.xml b/package.xml index ce58d73..f731b54 100644 --- a/package.xml +++ b/package.xml @@ -6,10 +6,9 @@ http://pear.php.net/dtd/package-2.0.xsd"> operator pecl.php.net Operator overloading for Objects - Operator overloading for: +, -, *, /, %, <<, >>, ., |, &, ^, ~, !, ++, --, -+=, -=, *=, /=, %=, <<=, >>=, .=, |=, &=, ^=, ~=, -==, !=, ===, !==, <, and <= operators. -Conditional support for > and >= available with application of a patch. + Operator overloading for: +, -, *, /, %, **, <<, >>, ., |, &, ^, ~, !, ++, --, ++=, -=, *=, /=, %=, **=, <<=, >>=, .=, |=, &=, ^=, ~=, +==, !=, ===, !==, <, <=, and <=> operators. @@ -18,11 +17,11 @@ Conditional support for > and >= available with application of a patch. pollita@php.net yes - 2009-11-05 - + 2017-03-08 + - 0.3 - 0.3 + 1.0 + 1.0 beta @@ -30,30 +29,26 @@ Conditional support for > and >= available with application of a patch. PHP -* Added support for comparator ops - -Note: ZE treats > style comparisons as backwards < comparisons, so what looks like a left-associative greater than becomes a right-associative less-than. -Because of this, overloading the > and >= operators for left-association requires application of a parser patch. +* 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 - + - - - - @@ -69,6 +64,26 @@ Because of this, overloading the > and >= operators for left-association r operator + + 2009-11-05 + + + 0.3 + 0.3 + + + beta + beta + + PHP + +* Added support for comparator ops + +Note: ZE treats > style comparisons as backwards < comparisons, so what looks like a left-associative greater than becomes a right-associative less-than. +Because of this, overloading the > and >= operators for left-association requires application of a parser patch. + + + 0.2 diff --git a/php_operator.h b/php_operator.h deleted file mode 100644 index 857f974..0000000 --- a/php_operator.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 5 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2006 The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.0 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_0.txt. | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Author: Sara Golemon | - +----------------------------------------------------------------------+ -*/ - -/* $Id$ */ - -#ifndef PHP_OPERATOR_H -#define PHP_OPERATOR_H - -#define PHP_OPERATOR_EXTNAME "operator" -#define PHP_OPERATOR_VERSION "0.4.0-dev" - -#if ZEND_MODULE_API_NO > 20121211 -#define ZEND_ENGINE_2_5 -#endif -#if ZEND_MODULE_API_NO > 20100524 -#define ZEND_ENGINE_2_4 -#endif -#if ZEND_MODULE_API_NO > 20090625 -#define ZEND_ENGINE_2_3 -#endif -#if ZEND_MODULE_API_NO > 20050922 -#define ZEND_ENGINE_2_2 -#endif -#if ZEND_MODULE_API_NO > 20050921 -#define ZEND_ENGINE_2_1 -#endif - -#ifdef ZEND_ENGINE_2_4 -# define PHP_OPERATOR_OP_TYPE(zop) (zop##_type) -# define PHP_OPERATOR_OP_U(zop) (zop) -# define PHP_OPERATOR_LITERAL_DC , const struct _zend_literal *key -# define PHP_OPERATOR_LITERAL_CC , key -# define PHP_OPERATOR_LITERAL_NULL_CC , NULL -#else -# define PHP_OPERATOR_OP_TYPE(zop) ((zop).op_type) -# define PHP_OPERATOR_OP_U(zop) ((zop).u) -# define PHP_OPERATOR_LITERAL_DC -# define PHP_OPERATOR_LITERAL_CC -# define PHP_OPERATOR_LITERAL_NULL_CC -#endif - -#if defined(ZEND_ENGINE_2) && !defined(ZEND_ENGINE_2_1) -typedef struct { - zval *var; -} zend_free_op; -#endif - -#ifndef EX_CV_NUM -# define EX_CV_NUM(ex, n) (&((ex)->CVs[(n)])) -#endif - -extern zend_module_entry operator_module_entry; -#define phpext_operator_ptr &operator_module_entry - -#endif - - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ diff --git a/tests/binary_assign_objdim.phpt b/tests/binary_assign_objdim.phpt deleted file mode 100644 index 3d2da12..0000000 --- a/tests/binary_assign_objdim.phpt +++ /dev/null @@ -1,43 +0,0 @@ ---TEST-- -binary assign obj/dim ops ---SKIPIF-- - ---FILE-- -value += $val; - } - - function __construct($init) { - $this->value = $init; - } -} - -class bar implements arrayaccess { - public $baz; - - function offsetget($ofs) { - return $this->{$ofs}; - } - - function offsetset($ofs,$val) { echo "argh"; } - function offsetunset($ofs) { echo "oof"; } - function offsetexists($ofs) { echo "ick"; return true; } -} - -$a = new foo(4); -$b = new bar; -$b->baz = $a; - -var_dump($b->baz += 10); -var_dump($b->baz += 5); -var_dump($b['baz'] += 10); -var_dump($b['baz'] += 5); ---EXPECT-- -int(14) -int(19) -int(29) -int(34) diff --git a/tests/compare2.phpt b/tests/compare2.phpt deleted file mode 100644 index 5f54b15..0000000 --- a/tests/compare2.phpt +++ /dev/null @@ -1,34 +0,0 @@ ---TEST-- -Extended comparison ops ---SKIPIF-- - ---FILE-- -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) diff --git a/tests/incdec_obj.phpt b/tests/incdec_obj.phpt deleted file mode 100644 index f5ee749..0000000 --- a/tests/incdec_obj.phpt +++ /dev/null @@ -1,65 +0,0 @@ ---TEST-- -Inc/Dec obj ops ---SKIPIF-- - ---FILE-- -value++; - } - - function __post_dec() { - return $this->value--; - } - - function __pre_inc() { - $this->value++; - return $this->value; - } - - function __pre_dec() { - $this->value--; - return $this->value; - } - - function __construct($init) { - $this->value = $init; - } -} - -class bar { - public $baz; -} - -$c = new foo(7); -$d = new bar; -$d->baz = $c; - -for($i = 0; $i < 3; $i++) { - var_dump($d->baz++); -} -for($i = 0; $i < 3; $i++) { - var_dump($d->baz--); -} -for($i = 0; $i < 3; $i++) { - var_dump(++$d->baz); -} -for($i = 0; $i < 3; $i++) { - var_dump(--$d->baz); -} ---EXPECT-- -int(7) -int(8) -int(9) -int(10) -int(9) -int(8) -int(8) -int(9) -int(10) -int(9) -int(8) -int(7)