8 Commits
php5 ... master

Author SHA1 Message Date
Peter Kokot
ac217a41eb Remove unused Git attributes ident
The `$Id$` keywords were used in CVS and Subversion where they can be
substituted with filename, last revision number change, last changed
date, and last user who changed it.

In Git this functionality is different and can be done with Git
attribute ident. These need to be defined manually for each file in the
`.gitattributes` file and are afterwards replaced with 40-character
hexadecimal blob object name which is based only on the particular file
contents.

This patch simplifies handling of `$Id$` keywords by removing them since
they are not used anymore.
2018-10-04 07:41:13 +02:00
Peter Kokot
f2ccb4a634 Fix some minor whitespace issues
- trim trailing whitespace
- phpt closing tag
- final EOL(s) trimmed and synced
2018-10-04 07:39:54 +02:00
Nat Ryall
32242463b2 Update package.xml
Fix for failed compile due to erroneous tag
2018-10-04 07:37:27 +02:00
Sara Golemon
39815275d8 Sigh, typos... 2017-03-09 15:02:37 -08:00
Sara Golemon
d270470099 Add support for is_greater(_or_equal) back
Support still requires a patch to the runtime,
but it's a really small patch now.
2017-03-09 14:59:26 -08:00
SvenRtbg
063bf71387 Fix typo 2017-03-09 10:50:04 -08:00
Sara Golemon
13d22dba51 Fix README table 2017-03-08 19:26:36 -08:00
Sara Golemon
ea41d2bed1 PHP7 rewrite 2017-03-08 19:23:58 -08:00
15 changed files with 322 additions and 939 deletions

1
.gitignore vendored
View File

@@ -17,6 +17,7 @@
/config.status
/config.sub
/configure
/configure.ac
/configure.in
/install-sh
/libtool

View File

@@ -1,3 +1,2 @@
operator
Sara Golemon

68
README.md Normal file
View File

@@ -0,0 +1,68 @@
# 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 &#x7c; $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 | `__is_greater($arg)` &#42; |
| $o >= $arg | `__is_greater_or_equal($arg)` &#42; |
| $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 &#x7c;= $arg | `__assign_bw_or($arg)` |
| $o &= $arg | `__assign_bw_and($arg)` |
| $o ^= $arg | `__assign_bw_xor($arg)` |
&#42; - `__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.

View File

@@ -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); }

View File

@@ -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); }

View File

@@ -1,4 +1,3 @@
dnl $Id$
dnl config.m4 for extension operators
PHP_ARG_ENABLE(operator, whether to enable operator overload support,

View File

@@ -1,4 +1,3 @@
// $Id$
// vim:ft=javascript
ARG_ENABLE("operator", "enable operator overload support", "no");
@@ -7,4 +6,3 @@ if (PHP_OPERATOR != "no") {
AC_DEFINE("ZEND_VM_KIND", 1, "CFLAGS_OPERATOR");
EXTENSION("operator", "operator.c");
}

View File

@@ -1,618 +1,236 @@
/*
+----------------------------------------------------------------------+
| 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 <pollita@php.net> |
+----------------------------------------------------------------------+
*/
/* $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)
/* 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 */
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_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), method);
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;
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;
}
ALLOC_INIT_ZVAL(tmp);
return tmp;
/* {{{ 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;
}
/* }}} */
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);
}
/* {{{ 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 = 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 */
op1 = EX_VAR(opline->result.var);
} else {
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
}
ZVAL_DEREF(op1);
switch (opline->opcode) {
#define X(op, meth) \
case ZEND_##op:
BINARY_OPS(X)
BINARY_ASSIGN_OPS(X)
#undef X
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);
}
FREE_OP2
FREE_OP1
EX(opline) = opline + 1;
return ZEND_USER_OPCODE_CONTINUE;
}
/* }}} */
#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;
/* {{{ 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);
ALL_OPS(X)
#undef X
return SUCCESS;
}
/* }}} */
#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)
#endif

View File

@@ -6,11 +6,10 @@ http://pear.php.net/dtd/package-2.0.xsd">
<name>operator</name>
<channel>pecl.php.net</channel>
<summary>Operator overloading for Objects</summary>
<description>Operator overloading for: +, -, *, /, %, &lt;&lt;, &gt;&gt;, ., |, &amp;, ^, ~, !, ++, --,
+=, -=, *=, /=, %=, &lt;&lt;=, &gt;&gt;=, .=, |=, &amp;=, ^=, ~=,
==, !=, ===, !==, &lt;, and &lt;= operators.
Conditional support for &gt; and &gt;= available with application of a patch.
<description>Operator overloading for: +, -, *, /, %, **, &lt;&lt;, &gt;&gt;, ., |, &amp;, ^, ~, !, ++, --,
+=, -=, *=, /=, %=, **=, &lt;&lt;=, &gt;&gt;=, .=, |=, &amp;=, ^=, ~=,
==, !=, ===, !==, &lt;, &lt;=, and &lt;=&gt; operators.
</description>
<lead>
<name>Sara Golemon</name>
@@ -18,11 +17,11 @@ Conditional support for &gt; and &gt;= available with application of a patch.
<email>pollita@php.net</email>
<active>yes</active>
</lead>
<date>2009-11-05</date>
<time>17:54:16</time>
<date>2017-03-08</date>
<time>20:54:00</time>
<version>
<release>0.3</release>
<api>0.3</api>
<release>1.0</release>
<api>1.0</api>
</version>
<stability>
<release>beta</release>
@@ -30,30 +29,25 @@ Conditional support for &gt; and &gt;= available with application of a patch.
</stability>
<license uri="http://www.php.net/license">PHP</license>
<notes>
* Added support for comparator ops
Note: ZE treats &gt; style comparisons as backwards &lt; comparisons, so what looks like a left-associative greater than becomes a right-associative less-than.
Because of this, overloading the &gt; and &gt;= operators for left-association requires application of a parser patch.
* Rewrote for PHP7, dropped PHP5 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>
<contents>
<dir name="/">
<dir name="tests">
<file name="binary.phpt" role="test" />
<file name="binary_assign.phpt" role="test" />
<file name="binary_assign_objdim.phpt" role="test" />
<file name="bug56904.phpt" role="test" />
<file name="compare.phpt" role="test" />
<file name="compare2.phpt" role="test" />
<file name="incdec.phpt" role="test" />
<file name="unary.phpt" role="test" />
</dir> <!-- //tests -->
<file name="compare-greater-5.0.5.diff" role="src" />
<file name="compare-greater-5.1.2.diff" role="src" />
<file name="config.m4" role="src" />
<file name="config.w32" role="src" />
<file name="CREDITS" role="doc" />
<file name="EXPERIMENTAL" role="doc" />
<file name="operator.c" role="src" />
<file name="php_operator.h" role="src" />
</dir> <!-- / -->
</contents>
<dependencies>
@@ -69,6 +63,25 @@ Because of this, overloading the &gt; and &gt;= operators for left-association r
<providesextension>operator</providesextension>
<extsrcrelease />
<changelog>
<release>
<date>2009-11-05</date>
<time>17:54:16</time>
<version>
<release>0.3</release>
<api>0.3</api>
</version>
<stability>
<release>beta</release>
<api>beta</api>
</stability>
<license uri="http://www.php.net/license">PHP</license>
<notes>
* Added support for comparator ops
Note: ZE treats &gt; style comparisons as backwards &lt; comparisons, so what looks like a left-associative greater than becomes a right-associative less-than.
Because of this, overloading the &gt; and &gt;= operators for left-association requires application of a parser patch.
</notes>
</release>
<release>
<version>
<release>0.2</release>

13
php7-is_greater.diff Normal file
View 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;
}
/* }}} */

View File

@@ -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 <pollita@php.net> |
+----------------------------------------------------------------------+
*/
/* $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
*/

View File

@@ -1,43 +0,0 @@
--TEST--
binary assign obj/dim ops
--SKIPIF--
<?php if(!extension_loaded("operator")) print "skip"; ?>
--FILE--
<?php
class foo {
private $value;
function __assign_add($val) {
return $this->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)

View File

@@ -17,7 +17,7 @@ $bob->__assign_sl('abc');
var_dump($bob);
$bob <<= 'def';
var_dump($bob);
?>
--EXPECTF--
object(a)#%d (1) {
["v"]=>

View File

@@ -2,27 +2,21 @@
Extended comparison ops
--SKIPIF--
<?php if(!extension_loaded("operator")) print "skip";
if(!OPERATOR_COMPARE_PATCH) 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);

View File

@@ -1,65 +0,0 @@
--TEST--
Inc/Dec obj ops
--SKIPIF--
<?php if(!extension_loaded("operator")) print "skip"; ?>
--FILE--
<?php
class foo {
private $value;
function __post_inc() {
return $this->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)