package.xml 0000664 0001750 0001750 00000033144 14133502033 011646 0 ustar remi remi
uopz
pecl.php.net
User Operations for Zend
The uopz extension is focused on providing utilities to aid with unit testing PHP code.
It supports the following activities:
* Intercepting function execution
* Intercepting object creation
* Hooking into function execution
* Manipulation of function statics
* Manipulation of function flags
* Redefinition of constants
* Deletion of constants
* Runtime creation of functions and methods
Joe Watkins
krakjoe
pthreads@pthreads.org
yes
Remi Collet
remi
remi@php.net
yes
2021-10-19
7.1.1
7.1.0
stable
stable
PHP License
- fix PHP 8.1 compatibility
8.0.0
1.10
xdebug
2.9.3
uopz
2021-08-06
7.1.0
7.1.0
stable
stable
PHP License
- uopz_implement and uopz_extend have been dropped
- internal rewrite to improve stability and simplify
2021-07-28
7.0.0
6.0.0
stable
stable
PHP License
- Fix #145 uopz_find_hook segfault with PHP 8.0
- Fix #140 segfault with PHPUnit 9.5 caused by uopz_del_function
- Don't remove methods of immutable classes
- PHP 8 support
- Drop PHP 7 support
2020-06-30
6.1.2
6.0.0
stable
stable
PHP License
- make UOPZ compatible with Xdebug again (2.9.4+ required)
2019-09-18
6.1.1
6.0.0
stable
stable
PHP License
- Fix compatibility with 7.4.0RC1
- Fix gh#110 uopz_set_mock function does not work if xdebug is loaded
2019-05-27
6.1.0
6.0.0
stable
stable
PHP License
- Fix #109 uopz_set_hook closure receive extra arguments when function call
through call_user_func and call_user_func_array
- 7.4 support
2019-02-06
6.0.1
6.0.0
stable
stable
PHP License
- Add "uopz.exit" configuration option, to allow the execution of exit
opcodes or not (default=0 to keep current behavior)
- Improve opcache optimizer compatibility
- Display ini settings in module info
2019-01-30
6.0.0
6.0.0
stable
stable
PHP License
- Breaking change to uopz_set_mock: now behaves like the old test-helpers new overload
- Fixed redefine/undefine namespaced constants
- Fix flags being ignored when adding functions
- Remove executor hook for maximum compatibility
2019-01-02
5.1.0
5.1.0
stable
stable
PHP License
- Fix #89 uopz_flags bugs on 64bit windows
- Fix #87 segfault when hook throws fatal error
- Fix #86 interface support for uopz_set_return
- Fix #85 cuf/cufa bugs
- Fix #76 uopz_extend changing linkage
- Fix #73 cuf/cufa bugs
- Fix #68 hang when using anon class as mock
- Fix #64 segfault after uopz_set_static
- Fix #63 class constant redefinition depends on opcache
- Fix #61 mocking not working with xdebug
- Fix #51 hooks and returns bug
- Fix #42 uopz_set_mock not working in some cases
- Fix PHP 7.3 compatibility
2017-08-03
5.0.2
5.0.0
stable
stable
PHP License
- add uopz.disable ini switch (default 0)
- fix gh#43: setting hook on __invoke method doesn't work on call_user_func
- fix gh#48: segmentation fault (uopz_set_return)
- add 4 new functions:
- uopz_call_user_func(callable function, ... args)
- uopz_get_exit_status()
- uopz_allow_exit(bool allow)
- uopz_call_user_func_array(callable function, array args)
- fix PHP 7.1 compatibility
- fix PHP 7.2 compatibility
2016-04-13
5.0.1
5.0.0
stable
stable
PHP License
- PHP 7 compatibility
- new API, see documentation
2015-03-04
2.0.7
2.0.7
stable
stable
PHP License
fix bug in overriding methods in classes loaded prior to override
add ability to send object from ZEND_NEW handler
send exit parameter to overload function
fix bug in handling exit status code when overloading disabled
set exit status code when overloading enabled from return value
uopz-7.1.1/src/class.c 0000664 0001750 0001750 00000013312 14133502033 013223 0 ustar remi remi /*
+----------------------------------------------------------------------+
| uopz |
+----------------------------------------------------------------------+
| Copyright (c) Joe Watkins 2016-2021 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 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_01.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: Joe Watkins |
+----------------------------------------------------------------------+
*/
#ifndef UOPZ_CLASS
#define UOPZ_CLASS
#include "php.h"
#include "uopz.h"
#include "util.h"
#include "class.h"
ZEND_EXTERN_MODULE_GLOBALS(uopz);
#define uopz_get_scope(e) ((e) ? zend_get_executed_scope() : EG(fake_scope))
#define uopz_set_scope(s) EG(fake_scope) = (s)
void uopz_set_mock(zend_string *clazz, zval *mock) { /* {{{ */
zend_string *key = zend_string_tolower(clazz);
if (zend_hash_update(&UOPZ(mocks), key, mock)) {
zval_copy_ctor(mock);
}
zend_string_release(key);
} /* }}} */
void uopz_unset_mock(zend_string *clazz) { /* {{{ */
zend_string *key = zend_string_tolower(clazz);
if (!zend_hash_exists(&UOPZ(mocks), key)) {
uopz_exception(
"the class provided (%s) has no mock set",
ZSTR_VAL(clazz));
zend_string_release(key);
return;
}
zend_hash_del(&UOPZ(mocks), key);
zend_string_release(key);
} /* }}} */
int uopz_get_mock(zend_string *clazz, zval *return_value) { /* {{{ */
zval *mock = NULL;
zend_string *key = zend_string_tolower(clazz);
if (!(mock = zend_hash_find(&UOPZ(mocks), key))) {
zend_string_release(key);
return FAILURE;
}
ZVAL_COPY(return_value, mock);
zend_string_release(key);
return SUCCESS;
} /* }}} */
int uopz_find_mock(zend_string *clazz, zend_object **object, zend_class_entry **mock) { /* {{{ */
zend_string *key = zend_string_tolower(clazz);
zval *found = zend_hash_find(&UOPZ(mocks), key);
zend_string_release(key);
if (!found) {
return FAILURE;
}
if (Z_TYPE_P(found) == IS_STRING) {
*mock = zend_fetch_class_by_name(Z_STR_P(found), NULL, ZEND_FETCH_CLASS_EXCEPTION);
return *mock ? SUCCESS : FAILURE;
} else {
*mock = Z_OBJCE_P(found);
if (object) {
*object = Z_OBJ_P(found);
}
return SUCCESS;
}
} /* }}} */
void uopz_set_property(zval *object, zend_string *member, zval *value) { /* {{{ */
zend_class_entry *scope = uopz_get_scope(0);
zend_class_entry *ce = Z_OBJCE_P(object);
zend_property_info *info;
do {
uopz_set_scope(ce);
info = zend_get_property_info(ce, member, 1);
if (info && info != ZEND_WRONG_PROPERTY_INFO) {
break;
}
ce = ce->parent;
} while (ce);
if (info && info != ZEND_WRONG_PROPERTY_INFO) {
uopz_set_scope(info->ce);
} else {
uopz_set_scope(Z_OBJCE_P(object));
}
Z_OBJ_HT_P(object)
->write_property(Z_OBJ_P(object), member, value, NULL);
uopz_set_scope(scope);
} /* }}} */
void uopz_get_property(zval *object, zend_string *member, zval *value) { /* {{{ */
zend_class_entry *scope = uopz_get_scope(0);
zend_class_entry *ce = Z_OBJCE_P(object);
zend_property_info *info;
zval *prop, rv;
do {
uopz_set_scope(ce);
info = zend_get_property_info(ce, member, 1);
if (info && info != ZEND_WRONG_PROPERTY_INFO) {
break;
}
ce = ce->parent;
} while (ce);
if (info && info != ZEND_WRONG_PROPERTY_INFO) {
uopz_set_scope(info->ce);
} else {
uopz_set_scope(Z_OBJCE_P(object));
}
prop = Z_OBJ_HT_P(object)->read_property(
Z_OBJ_P(object), member, BP_VAR_R, NULL, &rv);
uopz_set_scope(scope);
ZVAL_COPY(value, prop);
} /* }}} */
void uopz_set_static_property(zend_class_entry *ce, zend_string *property, zval *value) { /* {{{ */
zend_class_entry *scope = uopz_get_scope(0);
zend_class_entry *seek = ce;
zend_property_info *info;
zval *prop;
do {
uopz_set_scope(seek);
info = zend_get_property_info(seek, property, 1);
if (info && info != ZEND_WRONG_PROPERTY_INFO) {
break;
}
seek = seek->parent;
} while (seek);
if (info && info != ZEND_WRONG_PROPERTY_INFO) {
uopz_set_scope(info->ce);
} else {
uopz_set_scope(ce);
}
prop = zend_std_get_static_property(uopz_get_scope(0), property, 1);
uopz_set_scope(scope);
if (!prop) {
uopz_exception(
"cannot set non-existent static property %s::%s",
ZSTR_VAL(ce->name),
ZSTR_VAL(property));
return;
}
zval_ptr_dtor(prop);
ZVAL_COPY(prop, value);
} /* }}} */
void uopz_get_static_property(zend_class_entry *ce, zend_string *property, zval *value) { /* {{{ */
zend_class_entry *scope = uopz_get_scope(0);
zend_class_entry *seek = ce;
zend_property_info *info;
zval *prop;
do {
uopz_set_scope(seek);
info = zend_get_property_info(seek, property, 1);
if (info && info != ZEND_WRONG_PROPERTY_INFO) {
break;
}
seek = seek->parent;
} while (seek);
if (info && info != ZEND_WRONG_PROPERTY_INFO) {
uopz_set_scope(info->ce);
} else {
uopz_set_scope(ce);
}
prop = zend_std_get_static_property(uopz_get_scope(0), property, 1);
uopz_set_scope(scope);
if (!prop) {
return;
}
ZVAL_COPY(value, prop);
} /* }}} */
#endif /* UOPZ_CLASS */
/*
* 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
*/
uopz-7.1.1/src/class.h 0000664 0001750 0001750 00000004013 14133502033 013226 0 ustar remi remi /*
+----------------------------------------------------------------------+
| uopz |
+----------------------------------------------------------------------+
| Copyright (c) Joe Watkins 2016-2021 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 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_01.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: Joe Watkins |
+----------------------------------------------------------------------+
*/
#ifndef UOPZ_CLASS_H
#define UOPZ_CLASS_H
void uopz_set_mock(zend_string *clazz, zval *mock);
void uopz_unset_mock(zend_string *clazz);
zend_bool uopz_extend(zend_class_entry *clazz, zend_class_entry *parent);
zend_bool uopz_implement(zend_class_entry *clazz, zend_class_entry *interface);
int uopz_get_mock(zend_string *clazz, zval *return_value);
int uopz_find_mock(zend_string *clazz, zend_object **object, zend_class_entry **mock);
void uopz_set_property(zval *object, zend_string *member, zval *value);
void uopz_get_property(zval *object, zend_string *member, zval *value);
void uopz_set_static_property(zend_class_entry *ce, zend_string *property, zval *value);
void uopz_get_static_property(zend_class_entry *ce, zend_string *property, zval *value);
#endif /* UOPZ_CLASS_H */
/*
* 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
*/
uopz-7.1.1/src/constant.c 0000664 0001750 0001750 00000010221 14133502033 013743 0 ustar remi remi /*
+----------------------------------------------------------------------+
| uopz |
+----------------------------------------------------------------------+
| Copyright (c) Joe Watkins 2016-2021 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 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_01.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: Joe Watkins |
+----------------------------------------------------------------------+
*/
#ifndef UOPZ_CONSTANT
#define UOPZ_CONSTANT
#include "php.h"
#include "uopz.h"
#include "util.h"
#include "constant.h"
/* {{{ */
zend_bool uopz_constant_redefine(zend_class_entry *clazz, zend_string *name, zval *variable) {
HashTable *table = clazz ? &clazz->constants_table : EG(zend_constants);
zend_string *key = zend_string_copy(name);
zend_constant *zconstant = zend_hash_find_ptr(table, key);
if (!zconstant && !clazz) {
const char *ns = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
size_t nss;
if (ns) {
zend_string *heap = zend_string_tolower(key);
ns++;
nss = (ZSTR_VAL(name) + ZSTR_LEN(name)) - ns;
memcpy(&ZSTR_VAL(heap)[ZSTR_LEN(heap) - nss], ns, nss);
zconstant = zend_hash_find_ptr(table, heap);
zend_string_release(key);
key = heap;
}
}
if (!zconstant) {
if (!clazz) {
zend_constant create;
ZVAL_COPY(&create.value, variable);
ZEND_CONSTANT_SET_FLAGS(&create, CONST_CS, PHP_USER_CONSTANT);
create.name = zend_string_copy(key);
zend_register_constant(&create);
} else {
zend_declare_class_constant(clazz,
ZSTR_VAL(name), ZSTR_LEN(name), variable);
Z_TRY_ADDREF_P(variable);
}
zend_string_release(key);
return 1;
}
if (!clazz) {
if (ZEND_CONSTANT_MODULE_NUMBER(zconstant) == PHP_USER_CONSTANT) {
zval_dtor(&zconstant->value);
ZVAL_COPY(&zconstant->value, variable);
} else {
uopz_exception(
"failed to redefine the internal %s, not allowed", ZSTR_VAL(name));
zend_string_release(key);
return 0;
}
} else {
zend_hash_del(table, key);
zend_declare_class_constant(clazz,
ZSTR_VAL(name), ZSTR_LEN(name), variable);
Z_TRY_ADDREF_P(variable);
}
zend_string_release(key);
return 1;
} /* }}} */
/* {{{ */
zend_bool uopz_constant_undefine(zend_class_entry *clazz, zend_string *name) {
zend_constant *zconstant;
HashTable *table = clazz ? &clazz->constants_table : EG(zend_constants);
zend_string *heap = NULL;
if (!(zconstant = zend_hash_find_ptr(table, name))) {
if (!clazz) {
const char *ns = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
size_t nss;
if (ns) {
heap = zend_string_tolower(name);
ns++;
nss = (ZSTR_VAL(name) + ZSTR_LEN(name)) - ns;
memcpy(&ZSTR_VAL(heap)[ZSTR_LEN(heap) - nss], ns, nss);
zconstant = zend_hash_find_ptr(table, heap);
if (!zconstant) {
zend_string_release(heap);
return 0;
}
name = heap;
goto _uopz_constant_undefine;
}
}
return 0;
}
_uopz_constant_undefine:
if (!clazz) {
if (ZEND_CONSTANT_MODULE_NUMBER(zconstant) != PHP_USER_CONSTANT) {
uopz_exception(
"failed to undefine the internal constant %s, not allowed", ZSTR_VAL(name));
if (heap) {
zend_string_release(heap);
}
return 0;
}
zend_hash_del(table, name);
if (heap) {
zend_string_release(heap);
}
return 1;
}
zend_hash_del(table, name);
return 1;
} /* }}} */
#endif /* UOPZ_CONSTANT */
/*
* 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
*/
uopz-7.1.1/src/constant.h 0000664 0001750 0001750 00000002761 14133502033 013762 0 ustar remi remi /*
+----------------------------------------------------------------------+
| uopz |
+----------------------------------------------------------------------+
| Copyright (c) Joe Watkins 2016-2021 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 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_01.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: Joe Watkins |
+----------------------------------------------------------------------+
*/
#ifndef UOPZ_CONSTANT_H
#define UOPZ_CONSTANT_H
zend_bool uopz_constant_redefine(zend_class_entry *clazz, zend_string *name, zval *variable);
zend_bool uopz_constant_undefine(zend_class_entry *clazz, zend_string *name);
#endif /* UOPZ_CONSTANT_H */
/*
* 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
*/
uopz-7.1.1/src/executors.c 0000664 0001750 0001750 00000004417 14133502033 014145 0 ustar remi remi /*
+----------------------------------------------------------------------+
| uopz |
+----------------------------------------------------------------------+
| Copyright (c) Joe Watkins 2016-2021 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 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_01.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: Joe Watkins |
+----------------------------------------------------------------------+
*/
#ifndef UOPZ_EXECUTORS
#define UOPZ_EXECUTORS
#include "php.h"
#include "uopz.h"
#include "executors.h"
ZEND_EXTERN_MODULE_GLOBALS(uopz);
typedef void (*zend_execute_internal_f) (zend_execute_data *, zval *);
void php_uopz_execute_internal(zend_execute_data *execute_data, zval *return_value);
zend_execute_internal_f zend_execute_internal_function;
void php_uopz_execute_internal(zend_execute_data *execute_data, zval *return_value);
void uopz_executors_init(void) { /* {{{ */
zend_execute_internal_function = zend_execute_internal;
zend_execute_internal = php_uopz_execute_internal;
} /* }}} */
void uopz_executors_shutdown(void) { /* {{{ */
zend_execute_internal = zend_execute_internal_function;
} /* }}} */
void php_uopz_execute_internal(zend_execute_data *execute_data, zval *return_value) { /* {{{ LCOV_EXCL_START */
if (zend_execute_internal_function) {
zend_execute_internal_function(execute_data, return_value);
} else execute_internal(execute_data, return_value);
} /* LCOV_EXCL_STOP }}} */
#endif /* UOPZ_HANDLERS_H */
/*
* 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
*/
uopz-7.1.1/src/executors.h 0000664 0001750 0001750 00000002614 14133502033 014147 0 ustar remi remi /*
+----------------------------------------------------------------------+
| uopz |
+----------------------------------------------------------------------+
| Copyright (c) Joe Watkins 2016-2021 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 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_01.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: Joe Watkins |
+----------------------------------------------------------------------+
*/
#ifndef UOPZ_EXECUTORS_H
#define UOPZ_EXECUTORS_H
void uopz_executors_init(void);
void uopz_executors_shutdown(void);
#endif /* UOPZ_EXECUTORS_H */
/*
* 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
*/
uopz-7.1.1/src/function.c 0000664 0001750 0001750 00000025504 14133502033 013751 0 ustar remi remi /*
+----------------------------------------------------------------------+
| uopz |
+----------------------------------------------------------------------+
| Copyright (c) Joe Watkins 2016-2021 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 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_01.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: Joe Watkins |
+----------------------------------------------------------------------+
*/
#ifndef UOPZ_FUNCTION
#define UOPZ_FUNCTION
#include "php.h"
#include "uopz.h"
#include "util.h"
#include "function.h"
#include
ZEND_EXTERN_MODULE_GLOBALS(uopz);
static zend_function* uopz_copy_function(zend_class_entry *scope, zend_string *name, zend_object *closure, zend_long flags) { /* {{{ */
zend_function *copy = (zend_function*) zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
memcpy(copy, zend_get_closure_method_def(closure), sizeof(zend_op_array));
copy->op_array.fn_flags &= ~ZEND_ACC_CLOSURE|ZEND_ACC_IMMUTABLE|ZEND_ACC_ARENA_ALLOCATED;
copy->op_array.function_name = zend_string_copy(name);
copy->op_array.scope = scope;
if (flags & ZEND_ACC_PPP_MASK) {
copy->op_array.fn_flags &= ~ZEND_ACC_PPP_MASK;
copy->op_array.fn_flags |= flags & ZEND_ACC_PPP_MASK;
} else {
copy->op_array.fn_flags |= ZEND_ACC_PUBLIC;
}
if (flags & ZEND_ACC_STATIC) {
copy->op_array.fn_flags |= ZEND_ACC_STATIC;
}
if (copy->op_array.static_variables) {
copy->op_array.static_variables = zend_array_dup(copy->op_array.static_variables);
#if PHP_VERSION_ID > 80100
ZEND_MAP_PTR_INIT(
copy->op_array.static_variables_ptr, copy->op_array.static_variables);
#else
ZEND_MAP_PTR_INIT(
copy->op_array.static_variables_ptr, ©->op_array.static_variables);
#endif
} else {
ZEND_MAP_PTR_INIT(copy->op_array.static_variables_ptr, NULL);
}
if (copy->op_array.refcount) {
(*copy->op_array.refcount)++;
}
copy->op_array.fn_flags |= ZEND_ACC_UOPZ;
return copy;
} /* }}} */
zend_bool uopz_add_function(zend_class_entry *clazz, zend_string *name, zval *closure, zend_long flags, zend_bool all) { /* {{{ */
HashTable *table = clazz ? &clazz->function_table : CG(function_table);
zend_string *key;
zend_function *function = NULL;
if (clazz && clazz->ce_flags & ZEND_ACC_IMMUTABLE) {
uopz_exception(
"cannot add method %s::%s to immutable class, use uopz_set_return instead",
ZSTR_VAL(clazz->name),
ZSTR_VAL(name));
return 0;
}
key = zend_string_tolower(name);
key = zend_new_interned_string(key);
if (zend_hash_exists(table, key)) {
if (clazz) {
uopz_exception(
"will not replace existing method %s::%s, use uopz_set_return instead",
ZSTR_VAL(clazz->name),
ZSTR_VAL(name));
} else {
uopz_exception(
"will not replace existing function %s, use uopz_set_return instead",
ZSTR_VAL(name));
}
zend_string_release(key);
return 0;
}
function = uopz_copy_function(clazz, name, Z_OBJ_P(closure), flags);
zend_hash_update_ptr(table, key, (void*) function);
if (clazz) {
if (all) {
zend_class_entry *next;
ZEND_HASH_FOREACH_PTR(CG(class_table), next) {
if (next->parent == clazz) {
if (zend_hash_exists(&next->function_table, key)) {
continue;
}
uopz_add_function(next, name, closure, flags, all);
}
} ZEND_HASH_FOREACH_END();
}
uopz_handle_magic(clazz, name, function);
}
zend_string_release(key);
return 1;
} /* }}} */
zend_bool uopz_del_function(zend_class_entry *clazz, zend_string *name, zend_bool all) { /* {{{ */
HashTable *table = clazz ? &clazz->function_table : CG(function_table);
zend_string *key = zend_string_tolower(name);
zend_function *function = zend_hash_find_ptr(table, key);
if (!function) {
if (clazz) {
uopz_exception(
"cannot delete method %s::%s, it does not exist",
ZSTR_VAL(clazz->name),
ZSTR_VAL(name));
} else {
uopz_exception(
"cannot delete function %s, it does not exist",
ZSTR_VAL(name));
}
zend_string_release(key);
return 0;
}
if (!(function->common.fn_flags & ZEND_ACC_UOPZ)) {
if (clazz) {
uopz_exception(
"cannot delete method %s::%s, it was not added by uopz",
ZSTR_VAL(clazz->name),
ZSTR_VAL(name));
} else {
uopz_exception(
"cannot delete function %s, it was not added by uopz",
ZSTR_VAL(name));
}
zend_string_release(key);
return 0;
}
if (clazz && all) {
zend_class_entry *next;
ZEND_HASH_FOREACH_PTR(CG(class_table), next) {
if (next->parent == clazz) {
if (!zend_hash_exists(&next->function_table, key)) {
continue;
}
uopz_del_function(next, name, all);
}
} ZEND_HASH_FOREACH_END();
}
zend_hash_del(table, key);
zend_string_release(key);
return 1;
} /* }}} */
/* {{{ */
void uopz_flags(zend_class_entry *clazz, zend_string *name, zend_long flags, zval *return_value) {
HashTable *table = clazz ? &clazz->function_table : CG(function_table);
zend_long current = 0;
if (clazz && (!name || !ZSTR_LEN(name))) {
if (flags == ZEND_LONG_MAX) {
RETURN_LONG(clazz->ce_flags);
}
if (flags & ZEND_ACC_PPP_MASK) {
uopz_exception(
"attempt to set public, private or protected on class entry %s, not allowed",
ZSTR_VAL(clazz->name));
return;
}
if (flags & ZEND_ACC_STATIC) {
uopz_exception(
"attempt to set static on class entry %s, not allowed",
ZSTR_VAL(clazz->name));
return;
}
if (clazz->ce_flags & ZEND_ACC_IMMUTABLE) {
uopz_exception(
"attempt to set flags of immutable class entry %s, not allowed",
ZSTR_VAL(clazz->name));
return;
}
current = clazz->ce_flags;
clazz->ce_flags = flags;
if (current & ZEND_ACC_LINKED) {
clazz->ce_flags |= ZEND_ACC_LINKED;
}
RETURN_LONG(current);
}
zend_function *function = uopz_find_function(table, name);
if (!function) {
if (clazz) {
uopz_exception(
"failed to set or get flags of method %s::%s, it does not exist",
ZSTR_VAL(clazz->name), ZSTR_VAL(name));
} else {
uopz_exception(
"failed to set or get flags of function %s, it does not exist",
ZSTR_VAL(name));
}
return;
}
if (flags == ZEND_LONG_MAX) {
RETURN_LONG(function->common.fn_flags);
}
current = function->common.fn_flags;
if (flags) {
if (function->common.fn_flags & ZEND_ACC_IMMUTABLE) {
uopz_exception(
"attempt to set flags of immutable function entry %s, not allowed",
ZSTR_VAL(name));
return;
}
/* Only allow changing a whitelist of flags, don't allow modifying internal flags. */
uint32_t allowed_flags = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC | ZEND_ACC_FINAL;
function->common.fn_flags =
(function->common.fn_flags & ~allowed_flags) | (flags & allowed_flags);
}
RETURN_LONG(current);
} /* }}} */
zend_bool uopz_set_static(zend_class_entry *clazz, zend_string *function, zval *statics) { /* {{{ */
zend_function *entry;
zend_string *k = NULL;
zval *v = NULL;
if (clazz) {
entry = uopz_find_function(&clazz->function_table, function);
if (!entry) {
uopz_exception(
"failed to set statics in method %s::%s, it does not exist",
ZSTR_VAL(clazz->name), ZSTR_VAL(function));
return 0;
}
} else {
entry = uopz_find_function(CG(function_table), function);
if (!entry) {
uopz_exception(
"failed to set statics in function %s, it does not exist",
ZSTR_VAL(function));
return 0;
}
}
if (entry->type != ZEND_USER_FUNCTION) {
if (clazz) {
uopz_exception(
"failed to set statics in internal method %s::%s",
ZSTR_VAL(clazz->name), ZSTR_VAL(function));
} else {
uopz_exception(
"failed to set statics in internal function %s",
ZSTR_VAL(function));
}
return 0;
}
if (!entry->op_array.static_variables) {
if (clazz) {
uopz_exception(
"failed to set statics in method %s::%s, no statics declared",
ZSTR_VAL(clazz->name), ZSTR_VAL(function));
} else {
uopz_exception(
"failed to set statics in function %s, no statics declared",
ZSTR_VAL(function));
}
return 0;
}
HashTable *variables = ZEND_MAP_PTR_GET(entry->op_array.static_variables_ptr);
if (!variables) {
variables = zend_array_dup(entry->op_array.static_variables);
ZEND_MAP_PTR_SET(entry->op_array.static_variables_ptr, variables);
}
ZEND_HASH_FOREACH_STR_KEY_VAL(variables, k, v) {
zval *y;
if (Z_REFCOUNTED_P(v)) {
zval_ptr_dtor(v);
}
if (!(y = zend_hash_find(Z_ARRVAL_P(statics), k))) {
ZVAL_NULL(v);
continue;
}
ZVAL_COPY(v, y);
} ZEND_HASH_FOREACH_END();
return 1;
} /* }}} */
zend_bool uopz_get_static(zend_class_entry *clazz, zend_string *function, zval *return_value) { /* {{{ */
zend_function *entry;
if (clazz) {
entry = uopz_find_function(&clazz->function_table, function);
if (!entry) {
uopz_exception(
"failed to get statics from method %s::%s, it does not exist",
ZSTR_VAL(clazz->name), ZSTR_VAL(function));
return 0;
}
} else {
entry = uopz_find_function(CG(function_table), function);
if (!entry) {
uopz_exception(
"failed to get statics from function %s, it does not exist",
ZSTR_VAL(function));
return 0;
}
}
if (entry->type != ZEND_USER_FUNCTION) {
if (clazz) {
uopz_exception(
"failed to get statics from internal method %s::%s",
ZSTR_VAL(clazz->name), ZSTR_VAL(function));
} else {
uopz_exception(
"failed to get statics from internal function %s",
ZSTR_VAL(function));
}
return 0;
}
if (!entry->op_array.static_variables) {
if (clazz) {
uopz_exception(
"failed to set statics in method %s::%s, no statics declared",
ZSTR_VAL(clazz->name), ZSTR_VAL(function));
} else {
uopz_exception(
"failed to set statics in function %s, no statics declared",
ZSTR_VAL(function));
}
return 0;
}
HashTable *variables = ZEND_MAP_PTR_GET(entry->op_array.static_variables_ptr);
if (!variables) {
variables = zend_array_dup(entry->op_array.static_variables);
ZEND_MAP_PTR_SET(entry->op_array.static_variables_ptr, variables);
}
zval *val;
ZEND_HASH_FOREACH_VAL(variables, val) {
if (zval_update_constant_ex(val, entry->common.scope) != SUCCESS) {
return false;
}
} ZEND_HASH_FOREACH_END();
ZVAL_ARR(return_value, zend_array_dup(variables));
return 1;
} /* }}} */
#endif /* UOPZ_FUNCTION */
/*
* 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
*/
uopz-7.1.1/src/function.h 0000664 0001750 0001750 00000003520 14133502033 013750 0 ustar remi remi /*
+----------------------------------------------------------------------+
| uopz |
+----------------------------------------------------------------------+
| Copyright (c) Joe Watkins 2016-2021 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 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_01.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: Joe Watkins |
+----------------------------------------------------------------------+
*/
#ifndef UOPZ_FUNCTION_H
#define UOPZ_FUNCTION_H
#define ZEND_ACC_UOPZ (1<<30)
zend_bool uopz_add_function(zend_class_entry *clazz, zend_string *name, zval *closure, zend_long flags, zend_bool all);
zend_bool uopz_del_function(zend_class_entry *clazz, zend_string *name, zend_bool all);
void uopz_flags(zend_class_entry *clazz, zend_string *name, zend_long flags, zval *return_value);
zend_bool uopz_set_static(zend_class_entry *clazz, zend_string *function, zval *statics);
zend_bool uopz_get_static(zend_class_entry *clazz, zend_string *function, zval *return_value);
#endif /* UOPZ_FUNCTION_H */
/*
* 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
*/
uopz-7.1.1/src/handlers.c 0000664 0001750 0001750 00000033767 14133502033 013736 0 ustar remi remi /*
+----------------------------------------------------------------------+
| uopz |
+----------------------------------------------------------------------+
| Copyright (c) Joe Watkins 2016-2021 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 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_01.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: Joe Watkins |
+----------------------------------------------------------------------+
*/
#ifndef UOPZ_HANDLERS
#define UOPZ_HANDLERS
#include "php.h"
#include "uopz.h"
#include "class.h"
#include "return.h"
#include "hook.h"
#include "util.h"
ZEND_EXTERN_MODULE_GLOBALS(uopz);
#define UOPZ_HANDLERS_COUNT 12
#ifdef ZEND_VM_FP_GLOBAL_REG
# define UOPZ_OPCODE_HANDLER_ARGS
# define UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU
# define UOPZ_OPCODE_HANDLER_ARGS_CC
# define UOPZ_OPCODE_HANDLER_ARGS_DC
#else
# define UOPZ_OPCODE_HANDLER_ARGS zend_execute_data *execute_data
# define UOPZ_OPCODE_HANDLER_ARGS_DC , zend_execute_data *execute_data
# define UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU execute_data
# define UOPZ_OPCODE_HANDLER_ARGS_CC , execute_data
#endif
#ifdef ZEND_VM_IP_GLOBAL_REG
# define UOPZ_OPLINE opline
# define UOPZ_USE_OPLINE
# define UOPZ_LOAD_OPLINE() opline = EX(opline)
# define UOPZ_LOAD_NEXT_OPLINE() opline = EX(opline) + 1
# define UOPZ_SAVE_OPLINE() EX(opline) = opline
#else
# define UOPZ_OPLINE EX(opline)
# define UOPZ_USE_OPLINE const zend_op *opline = EX(opline)
# define UOPZ_LOAD_OPLINE()
# define UOPZ_LOAD_NEXT_OPLINE() UOPZ_OPLINE++
# define UOPZ_SAVE_OPLINE()
#endif
#define UOPZ_HANDLE_EXCEPTION() UOPZ_LOAD_OPLINE() return ZEND_USER_OPCODE_CONTINUE
#define UOPZ_VM_DISPATCH() return _uopz_vm_dispatch(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU)
#define UOPZ_VM_RETURN() return ZEND_USER_OPCODE_RETURN
#define UOPZ_VM_CONTINUE() return ZEND_USER_OPCODE_CONTINUE
#define UOPZ_VM_NEXT(e, n) do { \
if (e) { \
UOPZ_OPLINE = EX(opline) + (n); \
} else { \
UOPZ_OPLINE = opline + (n); \
} \
\
UOPZ_VM_CONTINUE(); \
} while(0)
#define UOPZ_VM_LEAVE() return ZEND_USER_OPCODE_LEAVE
#define RETURN_VALUE_USED(opline) ((opline)->result_type != IS_UNUSED)
#define EX_CONSTANT(e) RT_CONSTANT(EX(opline), e)
#define UOPZ_HANDLERS_DECL_BEGIN() uopz_vm_handler_t uopz_vm_handlers[UOPZ_HANDLERS_COUNT] = {
#define UOPZ_HANDLER_DECL(o, n) {o, &zend_vm_##n, uopz_vm_##n},
#define UOPZ_HANDLERS_DECL_END() {0}};
#define UOPZ_HANDLER_OVERLOAD(h) do { \
*(h)->zend = zend_get_user_opcode_handler((h)->opcode); \
zend_set_user_opcode_handler((h)->opcode, (h)->uopz); \
} while (0)
#define UOPZ_HANDLER_RESTORE(h) do { \
zend_set_user_opcode_handler((h)->opcode, *(h)->zend); \
} while (0)
typedef int (*zend_vm_handler_t) (UOPZ_OPCODE_HANDLER_ARGS);
typedef struct _uopz_vm_handler_t {
zend_uchar opcode;
zend_vm_handler_t *zend;
zend_vm_handler_t uopz;
} uopz_vm_handler_t;
zend_vm_handler_t zend_vm_exit;
zend_vm_handler_t zend_vm_new;
zend_vm_handler_t zend_vm_fetch_constant;
zend_vm_handler_t zend_vm_do_fcall;
zend_vm_handler_t zend_vm_do_ucall;
zend_vm_handler_t zend_vm_fetch_class;
zend_vm_handler_t zend_vm_fetch_class_constant;
zend_vm_handler_t zend_vm_init_fcall;
zend_vm_handler_t zend_vm_init_fcall_by_name;
zend_vm_handler_t zend_vm_init_ns_fcall_by_name;
zend_vm_handler_t zend_vm_init_method_call;
zend_vm_handler_t zend_vm_init_static_method_call;
int uopz_vm_exit(UOPZ_OPCODE_HANDLER_ARGS);
int uopz_vm_new(UOPZ_OPCODE_HANDLER_ARGS);
int uopz_vm_fetch_constant(UOPZ_OPCODE_HANDLER_ARGS);
int uopz_vm_do_fcall(UOPZ_OPCODE_HANDLER_ARGS);
int uopz_vm_do_ucall(UOPZ_OPCODE_HANDLER_ARGS);
int uopz_vm_fetch_class_constant(UOPZ_OPCODE_HANDLER_ARGS);
int uopz_vm_init_fcall(UOPZ_OPCODE_HANDLER_ARGS);
int uopz_vm_init_fcall_by_name(UOPZ_OPCODE_HANDLER_ARGS);
int uopz_vm_init_ns_fcall_by_name(UOPZ_OPCODE_HANDLER_ARGS);
int uopz_vm_init_method_call(UOPZ_OPCODE_HANDLER_ARGS);
int uopz_vm_init_static_method_call(UOPZ_OPCODE_HANDLER_ARGS);
UOPZ_HANDLERS_DECL_BEGIN()
UOPZ_HANDLER_DECL(ZEND_EXIT, exit)
UOPZ_HANDLER_DECL(ZEND_NEW, new)
UOPZ_HANDLER_DECL(ZEND_FETCH_CONSTANT, fetch_constant)
UOPZ_HANDLER_DECL(ZEND_FETCH_CLASS_CONSTANT, fetch_class_constant)
UOPZ_HANDLER_DECL(ZEND_DO_FCALL, do_fcall)
UOPZ_HANDLER_DECL(ZEND_DO_UCALL, do_ucall)
UOPZ_HANDLER_DECL(ZEND_INIT_FCALL, init_fcall)
UOPZ_HANDLER_DECL(ZEND_INIT_FCALL_BY_NAME, init_fcall_by_name)
UOPZ_HANDLER_DECL(ZEND_INIT_NS_FCALL_BY_NAME, init_ns_fcall_by_name)
UOPZ_HANDLER_DECL(ZEND_INIT_METHOD_CALL, init_method_call)
UOPZ_HANDLER_DECL(ZEND_INIT_STATIC_METHOD_CALL, init_static_method_call)
UOPZ_HANDLERS_DECL_END()
static zend_always_inline zval* uopz_get_zval(const zend_op *opline, int op_type, const znode_op *node, const zend_execute_data *execute_data) {
return zend_get_zval_ptr(opline, op_type, node, execute_data);
}
void uopz_handlers_init(void) {
uopz_vm_handler_t *handler = uopz_vm_handlers;
while (handler) {
if (!handler->opcode) {
break;
}
UOPZ_HANDLER_OVERLOAD(handler);
handler++;
}
}
void uopz_handlers_shutdown(void) {
uopz_vm_handler_t *handler = uopz_vm_handlers;
while (handler) {
if (!handler->opcode) {
break;
}
UOPZ_HANDLER_RESTORE(handler);
handler++;
}
}
static zend_always_inline int _uopz_vm_dispatch(UOPZ_OPCODE_HANDLER_ARGS) {
zend_vm_handler_t zend = NULL;
switch (EX(opline)->opcode) {
case ZEND_EXIT:
zend = zend_vm_exit;
break;
case ZEND_NEW:
zend = zend_vm_new;
break;
case ZEND_INIT_FCALL_BY_NAME:
zend = zend_vm_init_fcall_by_name;
break;
case ZEND_INIT_FCALL:
zend = zend_vm_init_fcall;
break;
case ZEND_INIT_NS_FCALL_BY_NAME:
zend = zend_vm_init_ns_fcall_by_name;
break;
case ZEND_INIT_METHOD_CALL:
zend = zend_vm_init_method_call;
break;
case ZEND_INIT_STATIC_METHOD_CALL:
zend = zend_vm_init_static_method_call;
break;
case ZEND_FETCH_CONSTANT:
zend = zend_vm_fetch_constant;
break;
case ZEND_FETCH_CLASS_CONSTANT:
zend = zend_vm_fetch_class_constant;
break;
case ZEND_DO_FCALL:
zend = zend_vm_do_fcall;
break;
case ZEND_DO_UCALL:
zend = zend_vm_do_ucall;
break;
}
if (zend) {
return zend(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);
}
return ZEND_USER_OPCODE_DISPATCH;
}
int uopz_vm_exit(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */
UOPZ_USE_OPLINE;
zval *estatus;
if (UOPZ(exit)) {
UOPZ_VM_DISPATCH();
}
if (opline->op1_type != IS_UNUSED) {
estatus = uopz_get_zval(
opline,
opline->op1_type,
&opline->op1,
execute_data);
do {
if (Z_TYPE_P(estatus) == IS_LONG) {
EG(exit_status) = Z_LVAL_P(estatus);
} else {
if (opline->op1_type & (IS_VAR|IS_CV) && Z_ISREF_P(estatus)) {
estatus = Z_REFVAL_P(estatus);
if (Z_TYPE_P(estatus) == IS_LONG) {
EG(exit_status) = Z_LVAL_P(estatus);
break;
}
}
}
} while (0);
ZVAL_COPY(&UOPZ(estatus), estatus);
}
if (opline < &EX(func)->op_array.opcodes[EX(func)->op_array.last - 1]) {
UOPZ_LOAD_NEXT_OPLINE();
while (opline->opcode == ZEND_EXT_STMT) {
UOPZ_LOAD_NEXT_OPLINE();
}
UOPZ_VM_CONTINUE();
} else {
UOPZ_VM_RETURN();
}
} /* }}} */
int uopz_vm_new(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */
UOPZ_USE_OPLINE;
zval *result;
zend_function *constructor;
zend_class_entry *ce;
zend_execute_data *call;
zend_object *obj = NULL;
UOPZ_SAVE_OPLINE();
if (opline->op1_type == IS_CONST) {
if (uopz_find_mock(Z_STR_P(EX_CONSTANT(opline->op1)), &obj, &ce) != SUCCESS) {
if (!EG(exception)) {
ce = zend_fetch_class_by_name(
Z_STR_P(EX_CONSTANT(opline->op1)),
Z_STR_P(EX_CONSTANT(opline->op1) + 1),
ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
}
}
} else if (opline->op1_type == IS_UNUSED) {
ce = zend_fetch_class(NULL, opline->op1.num);
if (!ce) {
ZVAL_UNDEF(EX_VAR(opline->result.var));
UOPZ_VM_DISPATCH();
}
uopz_find_mock(ce->name, &obj, &ce);
} else {
ce = Z_CE_P(
EX_VAR(opline->op1.var));
uopz_find_mock(ce->name, &obj, &ce);
}
if (ce == NULL) {
ZVAL_UNDEF(EX_VAR(opline->result.var));
UOPZ_VM_DISPATCH();
}
if (obj != NULL) {
ZVAL_OBJ(
EX_VAR(opline->result.var), obj);
Z_ADDREF_P(EX_VAR(opline->result.var));
if (opline->extended_value == 0 && (opline+1)->opcode == ZEND_DO_FCALL) {
UOPZ_VM_NEXT(0, 2);
}
call = zend_vm_stack_push_call_frame(
ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function,
opline->extended_value, NULL
);
call->prev_execute_data = EX(call);
EX(call) = call;
UOPZ_VM_NEXT(0, 1);
}
result = EX_VAR(opline->result.var);
if (object_init_ex(result, ce) != SUCCESS) {
ZVAL_UNDEF(result);
UOPZ_HANDLE_EXCEPTION();
}
constructor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result));
if (!constructor) {
if (EG(exception)) {
UOPZ_HANDLE_EXCEPTION();
}
if (opline->extended_value == 0 && (opline+1)->opcode == ZEND_DO_FCALL) {
UOPZ_VM_NEXT(0, 2);
}
call = zend_vm_stack_push_call_frame(
ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function,
opline->extended_value, NULL);
} else {
if (constructor->type == ZEND_USER_FUNCTION && !RUN_TIME_CACHE(&constructor->op_array)) {
void **run_time_cache =
zend_arena_alloc(&CG(arena), constructor->op_array.cache_size);
memset(run_time_cache, 0, constructor->op_array.cache_size);
ZEND_MAP_PTR_SET(constructor->op_array.run_time_cache, run_time_cache);
}
call = zend_vm_stack_push_call_frame(
ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS,
constructor,
opline->extended_value,
Z_OBJ_P(result)
);
Z_ADDREF_P(result);
}
call->prev_execute_data = EX(call);
EX(call) = call;
UOPZ_VM_NEXT(0, 1);
} /* }}} */
static zend_always_inline bool uopz_run_hook(zend_function *function, zend_execute_data *execute_data) { /* {{{ */
uopz_hook_t *uhook = uopz_find_hook(function);
if (uhook && !uhook->busy) {
uopz_execute_hook(uhook, execute_data, 0, 0);
if (UNEXPECTED(EG(exception))) {
return false;
}
}
return true;
} /* }}} */
/* {{{ */
static zend_always_inline int php_uopz_leave_helper(zend_execute_data *execute_data) {
zend_execute_data *call = EX(call);
if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) {
OBJ_RELEASE(Z_OBJ(call->This));
} else if (ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE) {
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func));
}
EX(call) = call->prev_execute_data;
EX(opline) = EX(opline) + 1;
zend_vm_stack_free_args(call);
zend_vm_stack_free_call_frame(call);
UOPZ_VM_LEAVE();
} /* }}} */
int uopz_vm_do_call_common(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */
zend_execute_data *call = EX(call);
if (call) {
const zend_op *opline = EX(opline);
if (!uopz_run_hook(call->func, call)) {
if (RETURN_VALUE_USED(opline)) {
ZVAL_UNDEF(EX_VAR(opline->result.var));
}
return php_uopz_leave_helper(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);
}
uopz_return_t *ureturn = uopz_find_return(call->func);
if (ureturn) {
zval rv, *return_value = RETURN_VALUE_USED(opline) ?
EX_VAR(opline->result.var) : &rv;
if (UOPZ_RETURN_IS_EXECUTABLE(ureturn)) {
if (UOPZ_RETURN_IS_BUSY(ureturn)) {
goto _uopz_vm_do_fcall_dispatch;
}
uopz_execute_return(ureturn, call, return_value);
if (!RETURN_VALUE_USED(opline)) {
zval_ptr_dtor(&rv);
}
return php_uopz_leave_helper(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);
}
if (RETURN_VALUE_USED(opline)) {
ZVAL_COPY(return_value, &ureturn->value);
}
return php_uopz_leave_helper(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);
}
}
_uopz_vm_do_fcall_dispatch:
UOPZ_VM_DISPATCH();
} /* }}} */
int uopz_vm_do_ucall(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */
return uopz_vm_do_call_common(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);
} /* }}} */
int uopz_vm_do_fcall(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */
return uopz_vm_do_call_common(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);
} /* }}} */
int uopz_vm_call_common(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */
CACHE_PTR(EX(opline)->result.num, NULL);
UOPZ_VM_DISPATCH();
} /* }}} */
int uopz_vm_init_fcall(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */
return uopz_vm_call_common(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);
} /* }}} */
int uopz_vm_init_fcall_by_name(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */
return uopz_vm_call_common(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);
} /* }}} */
int uopz_vm_init_ns_fcall_by_name(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */
return uopz_vm_call_common(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);
} /* }}} */
int uopz_vm_init_method_call(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */
if (EX(opline)->op2_type == IS_CONST) {
CACHE_PTR(EX(opline)->result.num, NULL);
CACHE_PTR(EX(opline)->result.num + sizeof(void*), NULL);
}
UOPZ_VM_DISPATCH();
} /* }}} */
int uopz_vm_init_static_method_call(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */
if (EX(opline)->op2_type == IS_CONST) {
if (EX(opline)->op1_type == IS_CONST) {
CACHE_PTR(EX(opline)->result.num + sizeof(void*), NULL);
} else {
CACHE_PTR(EX(opline)->result.num, NULL);
CACHE_PTR(EX(opline)->result.num + sizeof(void*), NULL);
}
}
UOPZ_VM_DISPATCH();
} /* }}} */
int uopz_vm_fetch_constant(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */
CACHE_PTR(EX(opline)->extended_value, NULL);
UOPZ_VM_DISPATCH();
} /* }}} */
int uopz_vm_fetch_class_constant(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */
CACHE_PTR(EX(opline)->extended_value + sizeof(void*), NULL);
if (EX(opline)->op1_type != IS_CONST) {
CACHE_PTR(EX(opline)->extended_value, NULL);
}
UOPZ_VM_DISPATCH();
} /* }}} */
#endif /* UOPZ_HANDLERS_H */
/*
* 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
*/
uopz-7.1.1/src/handlers.h 0000664 0001750 0001750 00000002607 14133502033 013730 0 ustar remi remi /*
+----------------------------------------------------------------------+
| uopz |
+----------------------------------------------------------------------+
| Copyright (c) Joe Watkins 2016-2021 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 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_01.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: Joe Watkins |
+----------------------------------------------------------------------+
*/
#ifndef UOPZ_HANDLERS_H
#define UOPZ_HANDLERS_H
void uopz_handlers_init(void);
void uopz_handlers_shutdown(void);
#endif /* UOPZ_HANDLERS_H */
/*
* 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
*/
uopz-7.1.1/src/hook.c 0000664 0001750 0001750 00000013476 14133502033 013071 0 ustar remi remi /*
+----------------------------------------------------------------------+
| uopz |
+----------------------------------------------------------------------+
| Copyright (c) Joe Watkins 2016-2021 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 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_01.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: Joe Watkins |
+----------------------------------------------------------------------+
*/
#ifndef UOPZ_HOOK
#define UOPZ_HOOK
#include "php.h"
#include "uopz.h"
#include "util.h"
#include "hook.h"
#include
ZEND_EXTERN_MODULE_GLOBALS(uopz);
zend_bool uopz_set_hook(zend_class_entry *clazz, zend_string *name, zval *closure) { /* {{{ */
HashTable *hooks;
uopz_hook_t hook;
zend_string *key = zend_string_tolower(name);
if (clazz) {
zend_function *function = uopz_find_method(clazz, key);
if (!function) {
uopz_exception(
"failed to set hook for %s::%s, the method does not exist",
ZSTR_VAL(clazz->name),
ZSTR_VAL(name));
zend_string_release(key);
return 0;
}
if (function->common.scope != clazz) {
uopz_exception(
"failed to set hook for %s::%s, the method is defined in %s",
ZSTR_VAL(clazz->name),
ZSTR_VAL(name),
ZSTR_VAL(function->common.scope->name));
zend_string_release(key);
return 0;
}
}
if (clazz) {
hooks = zend_hash_find_ptr(&UOPZ(hooks), clazz->name);
} else hooks = zend_hash_index_find_ptr(&UOPZ(hooks), 0);
if (!hooks) {
ALLOC_HASHTABLE(hooks);
zend_hash_init(hooks, 8, NULL, uopz_hook_free, 0);
if (clazz) {
zend_hash_update_ptr(&UOPZ(hooks), clazz->name, hooks);
} else zend_hash_index_update_ptr(&UOPZ(hooks), 0, hooks);
}
memset(&hook, 0, sizeof(uopz_hook_t));
hook.clazz = clazz;
hook.function = zend_string_copy(name);
ZVAL_COPY(&hook.closure, closure);
zend_hash_update_mem(
hooks, key, &hook, sizeof(uopz_hook_t));
zend_string_release(key);
return 1;
} /* }}} */
zend_bool uopz_unset_hook(zend_class_entry *clazz, zend_string *function) { /* {{{ */
HashTable *hooks;
zend_string *key = zend_string_tolower(function);
if (clazz) {
hooks = zend_hash_find_ptr(&UOPZ(hooks), clazz->name);
} else hooks = zend_hash_index_find_ptr(&UOPZ(hooks), 0);
if (!hooks || !zend_hash_exists(hooks, key)) {
zend_string_release(key);
return 0;
}
zend_hash_del(hooks, key);
zend_string_release(key);
return 1;
} /* }}} */
void uopz_get_hook(zend_class_entry *clazz, zend_string *function, zval *return_value) { /* {{{ */
HashTable *hooks;
uopz_hook_t *uhook;
zend_string *key = zend_string_tolower(function);
if (clazz) {
hooks = zend_hash_find_ptr(&UOPZ(hooks), clazz->name);
} else hooks = zend_hash_index_find_ptr(&UOPZ(hooks), 0);
if (!hooks || !zend_hash_exists(hooks, key)) {
zend_string_release(key);
return;
}
uhook = zend_hash_find_ptr(hooks, key);
ZVAL_COPY(return_value, &uhook->closure);
zend_string_release(key);
} /* }}} */
uopz_hook_t* uopz_find_hook(zend_function *function) { /* {{{ */
zend_string *key;
uopz_hook_t *uhook;
HashTable *hooks;
if ((function == NULL) ||
(function->common.function_name == NULL)) {
return NULL;
}
if (EG(flags) & EG_FLAGS_IN_SHUTDOWN) {
return NULL;
}
if (function->common.scope) {
hooks = zend_hash_find_ptr(&UOPZ(hooks), function->common.scope->name);
} else {
hooks = zend_hash_index_find_ptr(&UOPZ(hooks), 0);
}
if (!hooks) {
if (function->common.prototype &&
function->common.prototype->common.scope &&
function->common.prototype->common.scope->ce_flags & ZEND_ACC_INTERFACE) {
return uopz_find_hook(
function->common.prototype);
}
return NULL;
}
key = zend_string_tolower(function->common.function_name);
uhook = zend_hash_find_ptr(hooks, key);
zend_string_release(key);
return uhook;
} /* }}} */
void uopz_execute_hook(uopz_hook_t *uhook, zend_execute_data *execute_data, zend_bool skip, zend_bool variadic) { /* {{{ */
zend_fcall_info fci;
zend_fcall_info_cache fcc;
char *error = NULL;
zval closure, rv;
ZVAL_UNDEF(&rv);
uhook->busy = 1;
zend_create_closure(&closure, (zend_function*) zend_get_closure_method_def(Z_OBJ(uhook->closure)),
uhook->clazz, uhook->clazz, Z_OBJ(EX(This)) ? &EX(This) : NULL);
zend_fcall_info_init(&closure, 0, &fci, &fcc, NULL, &error);
if (!skip) {
fci.param_count = ZEND_CALL_NUM_ARGS(execute_data);
fci.params = ZEND_CALL_ARG(execute_data, 1);
} else {
if (variadic) {
zend_fcall_info_args_ex(
&fci,
fcc.function_handler,
ZEND_CALL_ARG(execute_data, 2));
} else {
fci.param_count = ZEND_CALL_NUM_ARGS(execute_data) - 1;
fci.params = ZEND_CALL_ARG(execute_data, 2);
}
}
fci.retval= &rv;
if (zend_call_function(&fci, &fcc) == SUCCESS) {
if (!Z_ISUNDEF(rv)) {
zval_ptr_dtor(&rv);
}
}
if (variadic) {
zend_fcall_info_args_clear(&fci, 1);
}
zval_ptr_dtor(&closure);
uhook->busy = 0;
} /* }}} */
void uopz_hook_free(zval *zv) { /* {{{ */
uopz_hook_t *uhook = Z_PTR_P(zv);
zend_string_release(uhook->function);
zval_ptr_dtor(&uhook->closure);
efree(uhook);
} /* }}} */
#endif /* UOPZ_HOOK */
/*
* 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
*/
uopz-7.1.1/src/hook.h 0000664 0001750 0001750 00000003567 14133502033 013076 0 ustar remi remi /*
+----------------------------------------------------------------------+
| uopz |
+----------------------------------------------------------------------+
| Copyright (c) Joe Watkins 2016-2021 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 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_01.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: Joe Watkins |
+----------------------------------------------------------------------+
*/
#ifndef UOPZ_HOOK_H
#define UOPZ_HOOK_H
typedef struct _uopz_hook_t {
zval closure;
zend_class_entry *clazz;
zend_string *function;
zend_bool busy;
} uopz_hook_t;
zend_bool uopz_set_hook(zend_class_entry *clazz, zend_string *name, zval *closure);
zend_bool uopz_unset_hook(zend_class_entry *clazz, zend_string *function);
void uopz_get_hook(zend_class_entry *clazz, zend_string *function, zval *return_value);
uopz_hook_t* uopz_find_hook(zend_function *function);
void uopz_execute_hook(uopz_hook_t *uhook, zend_execute_data *execute_data, zend_bool skip, zend_bool variadic);
void uopz_hook_free(zval *zv);
#endif /* UOPZ_HOOK_H */
/*
* 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
*/
uopz-7.1.1/src/return.c 0000664 0001750 0001750 00000014152 14133502033 013440 0 ustar remi remi /*
+----------------------------------------------------------------------+
| uopz |
+----------------------------------------------------------------------+
| Copyright (c) Joe Watkins 2016-2021 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 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_01.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: Joe Watkins |
+----------------------------------------------------------------------+
*/
#ifndef UOPZ_RETURN
#define UOPZ_RETURN
#include "php.h"
#include "uopz.h"
#include "util.h"
#include "return.h"
#include
ZEND_EXTERN_MODULE_GLOBALS(uopz);
zend_bool uopz_set_return(zend_class_entry *clazz, zend_string *name, zval *value, zend_bool execute) { /* {{{ */
HashTable *returns;
uopz_return_t ret;
zend_string *key = zend_string_tolower(name);
if (clazz) {
zend_function *function = uopz_find_method(clazz, key);
if (!function) {
uopz_exception(
"failed to set return for %s::%s, the method does not exist",
ZSTR_VAL(clazz->name),
ZSTR_VAL(name));
zend_string_release(key);
return 0;
}
if (function->common.scope != clazz) {
uopz_exception(
"failed to set return for %s::%s, the method is defined in %s",
ZSTR_VAL(clazz->name),
ZSTR_VAL(name),
ZSTR_VAL(function->common.scope->name));
zend_string_release(key);
return 0;
}
}
if (clazz) {
returns = zend_hash_find_ptr(&UOPZ(returns), clazz->name);
} else returns = zend_hash_index_find_ptr(&UOPZ(returns), 0);
if (!returns) {
ALLOC_HASHTABLE(returns);
zend_hash_init(returns, 8, NULL, uopz_return_free, 0);
if (clazz) {
zend_hash_update_ptr(&UOPZ(returns), clazz->name, returns);
} else zend_hash_index_update_ptr(&UOPZ(returns), 0, returns);
}
memset(&ret, 0, sizeof(uopz_return_t));
ret.clazz = clazz;
ret.function = zend_string_copy(name);
ZVAL_COPY(&ret.value, value);
ret.flags = execute ? UOPZ_RETURN_EXECUTE : 0;
zend_hash_update_mem(returns, key, &ret, sizeof(uopz_return_t));
zend_string_release(key);
return 1;
} /* }}} */
zend_bool uopz_unset_return(zend_class_entry *clazz, zend_string *function) { /* {{{ */
HashTable *returns;
zend_string *key = zend_string_tolower(function);
if (clazz) {
returns = zend_hash_find_ptr(&UOPZ(returns), clazz->name);
} else returns = zend_hash_index_find_ptr(&UOPZ(returns), 0);
if (!returns || !zend_hash_exists(returns, key)) {
zend_string_release(key);
return 0;
}
zend_hash_del(returns, key);
zend_string_release(key);
return 1;
} /* }}} */
void uopz_get_return(zend_class_entry *clazz, zend_string *function, zval *return_value) { /* {{{ */
HashTable *returns;
uopz_return_t *ureturn;
if (clazz) {
returns = zend_hash_find_ptr(&UOPZ(returns), clazz->name);
} else returns = zend_hash_index_find_ptr(&UOPZ(returns), 0);
if (!returns) {
return;
}
ureturn = zend_hash_find_ptr(returns, function);
if (!ureturn) {
return;
}
ZVAL_COPY(return_value, &ureturn->value);
} /* }}} */
uopz_return_t* uopz_find_return(zend_function *function) { /* {{{ */
zend_string *key;
uopz_return_t *ureturn;
HashTable *returns;
if ((function == NULL) ||
(function->common.function_name == NULL) ||
(function->common.fn_flags & ZEND_ACC_CLOSURE)) {
return NULL;
}
if (EG(flags) & EG_FLAGS_IN_SHUTDOWN) {
return NULL;
}
if (function->common.scope) {
returns = zend_hash_find_ptr(&UOPZ(returns), function->common.scope->name);
} else {
returns = zend_hash_index_find_ptr(&UOPZ(returns), 0);
}
if (!returns) {
if (function->common.prototype &&
function->common.prototype->common.scope &&
function->common.prototype->common.scope->ce_flags & ZEND_ACC_INTERFACE) {
return uopz_find_return(
function->common.prototype);
}
return NULL;
}
key = zend_string_tolower(function->common.function_name);
ureturn = zend_hash_find_ptr(returns, key);
zend_string_release(key);
return ureturn;
} /* }}} */
void uopz_execute_return(uopz_return_t *ureturn, zend_execute_data *execute_data, zval *return_value) { /* {{{ */
zend_fcall_info fci = empty_fcall_info;
zend_fcall_info_cache fcc = empty_fcall_info_cache;
char *error = NULL;
zval closure,
rv,
*result = return_value ? return_value : &rv;
ZVAL_UNDEF(&rv);
ureturn->flags ^= UOPZ_RETURN_BUSY;
zend_create_closure(&closure, (zend_function*) zend_get_closure_method_def(Z_OBJ(ureturn->value)),
ureturn->clazz, ureturn->clazz, Z_OBJ(EX(This)) ? &EX(This) : NULL);
zend_fcall_info_init(&closure, 0, &fci, &fcc, NULL, &error);
if (uopz_is_cuf(execute_data)) {
fci.params = ZEND_CALL_ARG(execute_data, 2);
fci.param_count = ZEND_CALL_NUM_ARGS(execute_data) - 1;
} else if (uopz_is_cufa(execute_data)) {
zend_fcall_info_args(&fci, ZEND_CALL_ARG(execute_data, 2));
} else {
fci.params = ZEND_CALL_ARG(execute_data, 1);
fci.param_count = ZEND_CALL_NUM_ARGS(execute_data);
}
fci.retval = result;
if (zend_call_function(&fci, &fcc) == SUCCESS) {
if (!return_value) {
if (!Z_ISUNDEF(rv)) {
zval_ptr_dtor(&rv);
}
}
}
zval_ptr_dtor(&closure);
if (uopz_is_cufa(execute_data)) {
zend_fcall_info_args_clear(&fci, 1);
}
ureturn->flags ^= UOPZ_RETURN_BUSY;
} /* }}} */
void uopz_return_free(zval *zv) { /* {{{ */
uopz_return_t *ureturn = Z_PTR_P(zv);
zend_string_release(ureturn->function);
zval_ptr_dtor(&ureturn->value);
efree(ureturn);
} /* }}} */
#endif /* UOPZ_RETURN */
/*
* 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
*/
uopz-7.1.1/src/return.h 0000664 0001750 0001750 00000004230 14133502033 013441 0 ustar remi remi /*
+----------------------------------------------------------------------+
| uopz |
+----------------------------------------------------------------------+
| Copyright (c) Joe Watkins 2016-2021 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 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_01.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: Joe Watkins |
+----------------------------------------------------------------------+
*/
#ifndef UOPZ_RETURN_H
#define UOPZ_RETURN_H
typedef struct _uopz_return_t {
zval value;
zend_uchar flags;
zend_class_entry *clazz;
zend_string *function;
} uopz_return_t;
#define UOPZ_RETURN_EXECUTE 0x00000001
#define UOPZ_RETURN_BUSY 0x00000010
#define UOPZ_RETURN_IS_EXECUTABLE(u) (((u)->flags & UOPZ_RETURN_EXECUTE) == UOPZ_RETURN_EXECUTE)
#define UOPZ_RETURN_IS_BUSY(u) (((u)->flags & UOPZ_RETURN_BUSY) == UOPZ_RETURN_BUSY)
zend_bool uopz_set_return(zend_class_entry *clazz, zend_string *name, zval *value, zend_bool execute);
zend_bool uopz_unset_return(zend_class_entry *clazz, zend_string *function);
void uopz_get_return(zend_class_entry *clazz, zend_string *function, zval *return_value);
uopz_return_t* uopz_find_return(zend_function *function);
void uopz_execute_return(uopz_return_t *ureturn, zend_execute_data *execute_data, zval *return_value);
void uopz_return_free(zval *zv);
#endif /* UOPZ_RETURN_H */
/*
* 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
*/
uopz-7.1.1/src/util.c 0000664 0001750 0001750 00000022625 14133502033 013102 0 ustar remi remi /*
+----------------------------------------------------------------------+
| uopz |
+----------------------------------------------------------------------+
| Copyright (c) Joe Watkins 2016-2021 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 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_01.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: Joe Watkins |
+----------------------------------------------------------------------+
*/
#ifndef UOPZ_UTIL
#define UOPZ_UTIL
#include "php.h"
#include "uopz.h"
#include "class.h"
#include "function.h"
#include "hook.h"
#include "return.h"
#include "util.h"
#include
ZEND_EXTERN_MODULE_GLOBALS(uopz);
static zend_internal_function *zend_call_user_func_ptr;
static zend_internal_function *zend_call_user_func_array_ptr;
static zend_internal_function *uopz_call_user_func_ptr;
static zend_internal_function *uopz_call_user_func_array_ptr;
static inline void uopz_table_dtor(zval *zv) { /* {{{ */
zend_hash_destroy(Z_PTR_P(zv));
efree(Z_PTR_P(zv));
} /* }}} */
/* {{{ */
typedef struct _uopz_magic_t {
const char *name;
size_t length;
int id;
} uopz_magic_t;
#define UOPZ_MAGIC(name, id) {name, sizeof(name)-1, id}
#define UOPZ_MAGIC_END {NULL, 0, 0L}
static const uopz_magic_t umagic[] = {
UOPZ_MAGIC(ZEND_CONSTRUCTOR_FUNC_NAME, 0),
UOPZ_MAGIC(ZEND_DESTRUCTOR_FUNC_NAME, 1),
UOPZ_MAGIC(ZEND_CLONE_FUNC_NAME, 2),
UOPZ_MAGIC(ZEND_GET_FUNC_NAME, 3),
UOPZ_MAGIC(ZEND_SET_FUNC_NAME, 4),
UOPZ_MAGIC(ZEND_UNSET_FUNC_NAME, 5),
UOPZ_MAGIC(ZEND_ISSET_FUNC_NAME, 6),
UOPZ_MAGIC(ZEND_CALL_FUNC_NAME, 7),
UOPZ_MAGIC(ZEND_CALLSTATIC_FUNC_NAME, 8),
UOPZ_MAGIC(ZEND_TOSTRING_FUNC_NAME, 9),
UOPZ_MAGIC("__serialize", 10),
UOPZ_MAGIC("__unserialize", 11),
UOPZ_MAGIC(ZEND_DEBUGINFO_FUNC_NAME, 12),
UOPZ_MAGIC_END
};
void uopz_handle_magic(zend_class_entry *clazz, zend_string *name, zend_function *function) { /* {{{ */
uopz_magic_t *magic;
for (magic = (uopz_magic_t*) umagic; magic->name; magic++) {
if (ZSTR_LEN(name) == magic->length &&
strncasecmp(ZSTR_VAL(name), magic->name, magic->length) == SUCCESS) {
switch (magic->id) {
case 0: clazz->constructor = function; break;
case 1: clazz->destructor = function; break;
case 2: clazz->clone = function; break;
case 3: clazz->__get = function; break;
case 4: clazz->__set = function; break;
case 5: clazz->__unset = function; break;
case 6: clazz->__isset = function; break;
case 7: clazz->__call = function; break;
case 8: clazz->__callstatic = function; break;
case 9: clazz->__tostring = function; break;
case 10: clazz->__serialize = function; break;
case 11: clazz->__unserialize = function; break;
case 12: clazz->__debugInfo = function; break;
}
return;
}
}
} /* }}} */
zend_function *uopz_find_method(zend_class_entry *ce, zend_string *name) { /* {{{ */
return uopz_find_function(&ce->function_table, name);
} /* }}} */
zend_function *uopz_find_function(HashTable *table, zend_string *name) { /* {{{ */
zend_string *key = zend_string_tolower(name);
zend_function *ptr = zend_hash_find_ptr(table, key);
zend_string_release(key);
return ptr;
} /* }}} */
zend_bool uopz_is_magic_method(zend_class_entry *clazz, zend_string *function) /* {{{ */
{
if (!clazz) {
return 0;
}
if (zend_string_equals_literal_ci(function, "__construct") ||
zend_string_equals_literal_ci(function, "__destruct") ||
zend_string_equals_literal_ci(function, "__clone") ||
zend_string_equals_literal_ci(function, "__get") ||
zend_string_equals_literal_ci(function, "__set") ||
zend_string_equals_literal_ci(function, "__unset") ||
zend_string_equals_literal_ci(function, "__isset") ||
zend_string_equals_literal_ci(function, "__call") ||
zend_string_equals_literal_ci(function, "__callstatic") ||
zend_string_equals_literal_ci(function, "__tostring") ||
zend_string_equals_literal_ci(function, "__debuginfo") ||
zend_string_equals_literal_ci(function, "__serialize") ||
zend_string_equals_literal_ci(function, "__unserialize") ||
zend_string_equals_literal_ci(function, "__sleep") ||
zend_string_equals_literal_ci(function, "__wakeup")) {
return 1;
}
return 0;
} /* }}} */
int uopz_clean_function(zval *zv) { /* {{{ */
zend_function *fp = Z_PTR_P(zv);
if (fp->type == ZEND_USER_FUNCTION && fp->common.fn_flags & ZEND_ACC_UOPZ) {
return ZEND_HASH_APPLY_REMOVE;
}
return ZEND_HASH_APPLY_KEEP;
} /* }}} */
int uopz_clean_class(zval *zv) { /* {{{ */
zend_class_entry *ce = Z_PTR_P(zv);
if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
return ZEND_HASH_APPLY_KEEP;
}
zend_hash_apply(
&ce->function_table, uopz_clean_function);
return ZEND_HASH_APPLY_KEEP;
} /* }}} */
static inline void uopz_caller_switch(zif_handler *old, zif_handler *new) {
zif_handler *current = old;
*old = *new;
*new = *current;
}
static void uopz_callers_init(void) { /* {{{ */
uopz_call_user_func_ptr = zend_hash_str_find_ptr(
CG(function_table), "uopz_call_user_func", sizeof("uopz_call_user_func")-1);
uopz_call_user_func_array_ptr = zend_hash_str_find_ptr(
CG(function_table), "uopz_call_user_func_array", sizeof("uopz_call_user_func_array")-1);
zend_call_user_func_ptr = zend_hash_str_find_ptr(
CG(function_table), "call_user_func", sizeof("call_user_func")-1);
zend_call_user_func_array_ptr = zend_hash_str_find_ptr(
CG(function_table), "call_user_func_array", sizeof("call_user_func_array")-1);
uopz_caller_switch(&zend_call_user_func_ptr->handler, &uopz_call_user_func_ptr->handler);
uopz_caller_switch(&zend_call_user_func_array_ptr->handler, &uopz_call_user_func_array_ptr->handler);
} /* }}} */
static void uopz_callers_shutdown(void) { /* {{{ */
uopz_caller_switch(&uopz_call_user_func_ptr->handler, &zend_call_user_func_ptr->handler);
uopz_caller_switch(&uopz_call_user_func_array_ptr->handler, &zend_call_user_func_array_ptr->handler);
} /* }}} */
#define UOPZ_CALL_HOOKS(variadic) do { \
if (!fcc.function_handler) { \
break; \
} \
\
{ \
uopz_hook_t *uhook = uopz_find_hook(fcc.function_handler); \
\
if (uhook && !uhook->busy) { \
uopz_execute_hook(uhook, execute_data, 1, variadic); \
} \
} \
\
do { \
uopz_return_t *ureturn = uopz_find_return(fcc.function_handler); \
\
if (ureturn) { \
if (UOPZ_RETURN_IS_EXECUTABLE(ureturn)) { \
if (UOPZ_RETURN_IS_BUSY(ureturn)) { \
break; \
} \
\
uopz_execute_return(ureturn, execute_data, return_value); \
return; \
} \
\
ZVAL_COPY(return_value, &ureturn->value); \
return; \
} \
} while (0); \
} while (0)
/* {{{ proto mixed uopz_call_user_func(callable function, ... args) */
PHP_FUNCTION(uopz_call_user_func) {
zval retval;
zend_fcall_info fci;
zend_fcall_info_cache fcc;
ZEND_PARSE_PARAMETERS_START(1, -1)
Z_PARAM_FUNC(fci, fcc)
Z_PARAM_VARIADIC_WITH_NAMED(fci.params, fci.param_count, fci.named_params)
ZEND_PARSE_PARAMETERS_END();
fci.retval = &retval;
UOPZ_CALL_HOOKS(0);
if (zend_call_function(&fci, &fcc) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
if (Z_ISREF(retval)) {
zend_unwrap_reference(&retval);
}
ZVAL_COPY_VALUE(return_value, &retval);
}
} /* }}} */
/* {{{ proto mixed uopz_call_user_func_array(callable function, array args) */
PHP_FUNCTION(uopz_call_user_func_array) {
HashTable *params;
zval retval;
zend_fcall_info fci;
zend_fcall_info_cache fcc;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_FUNC(fci, fcc)
Z_PARAM_ARRAY_HT(params)
ZEND_PARSE_PARAMETERS_END();
fci.named_params = params;
fci.retval = &retval;
UOPZ_CALL_HOOKS(1);
if (zend_call_function(&fci, &fcc) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
if (Z_ISREF(retval)) {
zend_unwrap_reference(&retval);
}
ZVAL_COPY_VALUE(return_value, &retval);
}
} /* }}} */
void uopz_request_init(void) { /* {{{ */
UOPZ(copts) = CG(compiler_options);
CG(compiler_options) |=
ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION |
ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION |
ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS |
ZEND_COMPILE_IGNORE_USER_FUNCTIONS |
ZEND_COMPILE_GUARDS;
zend_hash_init(&UOPZ(returns), 8, NULL, uopz_table_dtor, 0);
zend_hash_init(&UOPZ(mocks), 8, NULL, uopz_zval_dtor, 0);
zend_hash_init(&UOPZ(hooks), 8, NULL, uopz_table_dtor, 0);
{
char *report = getenv("UOPZ_REPORT_MEMLEAKS");
PG(report_memleaks) =
(report && report[0] == '1');
}
uopz_callers_init();
} /* }}} */
void uopz_request_shutdown(void) { /* {{{ */
CG(compiler_options) = UOPZ(copts);
zend_hash_apply(CG(class_table), uopz_clean_class);
zend_hash_apply(CG(function_table), uopz_clean_function);
zend_hash_destroy(&UOPZ(mocks));
zend_hash_destroy(&UOPZ(returns));
zend_hash_destroy(&UOPZ(hooks));
uopz_callers_shutdown();
} /* }}} */
#endif /* UOPZ_UTIL */
/*
* 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
*/
uopz-7.1.1/src/util.h 0000664 0001750 0001750 00000004576 14133502033 013114 0 ustar remi remi /*
+----------------------------------------------------------------------+
| uopz |
+----------------------------------------------------------------------+
| Copyright (c) Joe Watkins 2016-2021 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 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_01.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: Joe Watkins |
+----------------------------------------------------------------------+
*/
#ifndef UOPZ_UTIL_H
#define UOPZ_UTIL_H
extern PHP_FUNCTION(uopz_call_user_func);
extern PHP_FUNCTION(uopz_call_user_func_array);
void uopz_handle_magic(zend_class_entry *clazz, zend_string *name, zend_function *function);
zend_function *uopz_find_function(HashTable *table, zend_string *name);
zend_function *uopz_find_method(zend_class_entry *ce, zend_string *name);
zend_bool uopz_is_magic_method(zend_class_entry *clazz, zend_string *function);
int uopz_clean_function(zval *zv);
int uopz_clean_class(zval *zv);
void uopz_request_init(void);
void uopz_request_shutdown(void);
static inline void uopz_zval_dtor(zval *zv) { /* {{{ */
zval_ptr_dtor(zv);
} /* }}} */
static inline zend_bool uopz_is_cuf(zend_execute_data *execute_data) {
if (EX(func)->type == ZEND_INTERNAL_FUNCTION) {
if (EX(func)->internal_function.handler == zif_uopz_call_user_func) {
return 1;
}
}
return 0;
}
static inline zend_bool uopz_is_cufa(zend_execute_data *execute_data) {
if (EX(func)->type == ZEND_INTERNAL_FUNCTION) {
if (EX(func)->internal_function.handler == zif_uopz_call_user_func_array) {
return 1;
}
}
return 0;
}
#endif /* UOPZ_UTIL_H */
/*
* 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
*/
uopz-7.1.1/tests/bugs/0001-uopz_set_static.phpt 0000664 0001750 0001750 00000000530 14133502033 017755 0 ustar remi remi --TEST--
uopz_set_static with array
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
1]);
var_dump(Foo::bar());
?>
--EXPECTF--
int(%d)
int(1)
uopz-7.1.1/tests/bugs/0002-uopz_set_static_clear.phpt 0000664 0001750 0001750 00000000525 14133502033 021130 0 ustar remi remi --TEST--
uopz_set_static with empty array
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
1]);
var_dump(Foo::bar());
uopz_set_static ('Foo', 'bar', []);
var_dump(Foo::bar());
?>
--EXPECT--
int(1)
NULL
uopz-7.1.1/tests/bugs/0003-uopz_get_property.phpt 0000664 0001750 0001750 00000000645 14133502033 020347 0 ustar remi remi --TEST--
call uopz_get_property in a class scope
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
name;
}
}
class UM {
public function getProp($obj, $name) {
uopz_get_property($obj, $name);
}
}
$f = new Foo();
$um = New UM();
$um->getProp($f, 'name');
echo $f->getName();
?>
--EXPECT--
hello
uopz-7.1.1/tests/bugs/0004-uopz_set_property.phpt 0000664 0001750 0001750 00000000676 14133502033 020370 0 ustar remi remi --TEST--
call uopz_set_property in a class scope
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
name;
}
}
class UM {
public function setProp($obj, $name, $value) {
uopz_set_property($obj, $name, $value);
}
}
$f = new Foo();
$um = New UM();
$um->setProp($f, 'name', 'world');
echo $f->getName();
?>
--EXPECT--
world
uopz-7.1.1/tests/bugs/0005-uopz_set_return_prototype.phpt 0000664 0001750 0001750 00000000723 14133502033 022142 0 ustar remi remi --TEST--
prototype mixup setting return
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
bar = $value;
}
}
uopz_set_return (Foo::class, 'setBar', function ($value) {
echo "unused\n";
}, true);
class Foo2 extends Foo {
public function setBar ($value) {
$this->bar = 'expected';
}
}
$foo2 = new Foo2;
$foo2->setBar ('meh');
var_dump($foo2->bar);
--EXPECT--
string(8) "expected"
uopz-7.1.1/tests/bugs/0006-uopz-opcache-const-subst.phpt 0000664 0001750 0001750 00000001605 14133502033 021426 0 ustar remi remi --TEST--
opcache constant substitution disable
--EXTENSIONS--
uopz
--SKIPIF--
--INI--
uopz.disable=0
opcache.enabled=1
opcache.enable_cli=1
opcache.optimization_level=0x7FFFBFFF
--FILE--
callB () : $this->callA ();
}
private function callA () {
echo "A!" . PHP_EOL;
}
private function callB () {
echo "B!" . PHP_EOL;
}
}
uopz_set_return (Foo::class, 'callA', function () { echo "uopz A!" . PHP_EOL; }, true);
$x = new Foo;
var_dump ($x->__call (null, null));
uopz_redefine (Foo::class, 'USE_B', true);
var_dump ($x->__call (null, null));
?>
--EXPECT--
uopz A!
NULL
B!
NULL
uopz-7.1.1/tests/bugs/gh43.phpt 0000664 0001750 0001750 00000001164 14133502033 014731 0 ustar remi remi --TEST--
github #43
--DESCRIPTION--
Setting hook on __invoke method doesn't work on call_user_func
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
__invoke(2));
var_dump(call_user_func($h, 3));
uopz_set_return(Handler::class, '__invoke', 42);
var_dump($h(1));
var_dump($h->__invoke(2));
var_dump(call_user_func($h, 3));
--EXPECT--
hi!int(1)
hi!int(2)
hi!int(3)
hi!int(42)
hi!int(42)
hi!int(42)
uopz-7.1.1/tests/bugs/gh53.phpt 0000664 0001750 0001750 00000000567 14133502033 014740 0 ustar remi remi --TEST--
github #53
--DESCRIPTION--
uopz_redefine() refuses to redefine a constant as array
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
===DONE===
--EXPECT--
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(4)
}
===DONE===
uopz-7.1.1/tests/bugs/gh64.phpt 0000664 0001750 0001750 00000000605 14133502033 014733 0 ustar remi remi --TEST--
Segfault after uopz_set_static
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
3, 'b'=>7]);
$a = new A;
$a->fn();
print_r(uopz_get_static(A::class, "fn"));
--EXPECT--
Array
(
[a] => 1
)
Array
(
[a] => 4
)
uopz-7.1.1/tests/bugs/gh68.phpt 0000664 0001750 0001750 00000001056 14133502033 014740 0 ustar remi remi --TEST--
github #68: uopz_set_mock should not hang when mock with no-arg constructor is called with args
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
foo();
uopz_unset_mock(X::class);
uopz_set_mock(X::class, new Y);
$x = new X(0);
$x->foo();
?>
--EXPECT--
anonymous
Y
uopz-7.1.1/tests/bugs/gh73.phpt 0000664 0001750 0001750 00000001237 14133502033 014735 0 ustar remi remi --TEST--
bugs in cuf(a)
--EXTENSIONS--
uopz
--FILE--
emitEvent(1);
?>
--EXPECTF--
bool(true)
int(%d)
uopz-7.1.1/tests/bugs/gh99.phpt 0000664 0001750 0001750 00000000560 14133502033 014743 0 ustar remi remi --TEST--
get hook not case insensitive
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
--EXPECT--
string(11) "hook called"
int(123)
object(Closure)#1 (0) {
}
uopz-7.1.1/tests/bugs/gh100.phpt 0000664 0001750 0001750 00000000614 14133502033 015002 0 ustar remi remi --TEST--
get hook not case insensitive
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
--EXPECT--
1234
uopz-7.1.1/tests/bugs/gh102.phpt 0000664 0001750 0001750 00000000527 14133502033 015007 0 ustar remi remi --TEST--
uopz_undefine with namespaced constants does not delete constant
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
--EXPECTF--
Fatal error: Uncaught Error: Undefined constant %s in %s:7
Stack trace:
#0 {main}
thrown in %s on line 7
uopz-7.1.1/tests/bugs/gh106.phpt 0000664 0001750 0001750 00000000222 14133502033 015003 0 ustar remi remi --TEST--
uopz.exit enabled
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
uopz.exit=1
--FILE--
--EXPECT--
OK
uopz-7.1.1/tests/bugs/gh106a.phpt 0000664 0001750 0001750 00000000226 14133502033 015150 0 ustar remi remi --TEST--
uopz.exit disabled
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
uopz.exit=0
--FILE--
--EXPECT--
OK
OK
uopz-7.1.1/tests/bugs/gh109.phpt 0000664 0001750 0001750 00000001040 14133502033 015005 0 ustar remi remi --TEST--
hook closure call inconsistency
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
some(1, 2);
?>
--EXPECT--
array(2) {
[0]=>
int(1)
[1]=>
int(2)
}
array(2) {
[0]=>
int(1)
[1]=>
int(2)
}
array(2) {
[0]=>
int(1)
[1]=>
int(2)
}
uopz-7.1.1/tests/001.phpt 0000664 0001750 0001750 00000001775 14133502033 013534 0 ustar remi remi --TEST--
uopz_set_return
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
bar(1));
uopz_set_return(Foo::class, "bar", function(int $arg) : int {
return $arg * 2;
}, true);
var_dump($foo->bar(2));
try {
uopz_set_return(Foo::class, "nope", 1);
} catch(Throwable $t) {
var_dump($t->getMessage());
}
class Bar extends Foo {}
try {
uopz_set_return(Bar::class, "bar", null);
} catch (Throwable $t) {
var_dump($t->getMessage());
}
var_dump($foo::qux(10));
uopz_set_Return(Foo::class, "qux", function(int $arg) : int {
return $arg * 2;
}, true);
var_dump($foo::qux(20));
?>
--EXPECT--
bool(true)
bool(true)
int(4)
string(61) "failed to set return for Foo::nope, the method does not exist"
string(63) "failed to set return for Bar::bar, the method is defined in Foo"
int(10)
int(40)
uopz-7.1.1/tests/002.phpt 0000664 0001750 0001750 00000000734 14133502033 013527 0 ustar remi remi --TEST--
uopz_get_return
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
--EXPECT--
bool(true)
bool(true)
bool(true)
object(Closure)#1 (0) {
}
NULL
uopz-7.1.1/tests/003.phpt 0000664 0001750 0001750 00000001360 14133502033 013524 0 ustar remi remi --TEST--
uopz_unset_return
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
bar());
var_dump(uopz_unset_return(Foo::class, "bar"));
var_dump($foo->bar());
var_dump(uopz_unset_return(Foo::class, "nope"));
var_dump(uopz_set_return("bar", function(){
return true;
}, true));
var_dump(uopz_get_return("bar"));
var_dump(bar());
var_dump(uopz_unset_return("bar"));
var_dump(uopz_get_return(DateTime::class, "__construct"));
?>
--EXPECT--
bool(true)
bool(true)
bool(true)
bool(false)
bool(false)
bool(true)
object(Closure)#2 (0) {
}
bool(true)
bool(true)
NULL
uopz-7.1.1/tests/004.phpt 0000664 0001750 0001750 00000001460 14133502033 013526 0 ustar remi remi --TEST--
uopz_set_mock
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
getMessage(), "\n";
}
try {
Foo::newSelf();
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
?>
--EXPECTF--
object(Bar)#%d (0) {
}
int(1)
int(-1)
object(Foo)#%d (0) {
}
Class "DoesntExist" not found
Class "DoesntExist" not found
uopz-7.1.1/tests/005.phpt 0000664 0001750 0001750 00000000453 14133502033 013530 0 ustar remi remi --TEST--
uopz_get_mock
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
--EXPECT--
string(3) "Bar"
object(Bar)#1 (0) {
}
uopz-7.1.1/tests/006.phpt 0000664 0001750 0001750 00000000556 14133502033 013535 0 ustar remi remi --TEST--
uopz_unset_mock
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
--EXPECT--
string(3) "Bar"
NULL
OK
uopz-7.1.1/tests/007.phpt 0000664 0001750 0001750 00000003504 14133502033 013532 0 ustar remi remi --TEST--
uopz_get_static
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
method();
var_dump(uopz_get_static(Foo::class, "method"));
try {
uopz_get_static(Foo::class, "none");
} catch (RuntimeException $ex) {
var_dump($ex->getMessage());
}
try {
uopz_get_static("none");
} catch (RuntimeException $ex) {
var_dump($ex->getMessage());
}
try {
uopz_get_static(DateTime::class, "__construct");
} catch(RuntimeException $ex) {
var_dump($ex->getMessage());
}
try {
uopz_get_static("phpversion");
} catch(RuntimeException $ex) {
var_dump($ex->getMessage());
}
try {
uopz_get_static(Foo::class, "nostatics");
} catch(RuntimeException $ex) {
var_dump($ex->getMessage());
}
try {
uopz_get_static("nostatics");
} catch(RuntimeException $ex) {
var_dump($ex->getMessage());
}
?>
--EXPECTF--
array(2) {
["vars"]=>
array(5) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
[4]=>
int(5)
}
["bar"]=>
string(3) "bar"
}
array(2) {
["vars"]=>
array(6) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
[4]=>
int(5)
[5]=>
int(6)
}
["bar"]=>
string(3) "bar"
}
string(%d) "failed to get statics from method %s::%s, it does not exist"
string(%d) "failed to get statics from function %s, it does not exist"
string(%d) "failed to get statics from internal method %s::%s"
string(%d) "failed to get statics from internal function %s"
string(%d) "failed to set statics in method %s::%s, no statics declared"
string(%d) "failed to set statics in function %s, no statics declared"
uopz-7.1.1/tests/008.phpt 0000664 0001750 0001750 00000003352 14133502033 013534 0 ustar remi remi --TEST--
uopz_set_static
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
method();
var_dump(uopz_get_static(Foo::class, "method"));
uopz_set_static(Foo::class, "method", [
"vars" => []
]);
$foo->method();
var_dump(uopz_get_static(Foo::class, "method"));
try {
uopz_set_static(Foo::class, "none", []);
} catch(RuntimeException $ex) {
var_dump($ex->getMessage());
}
try {
uopz_set_static("none", []);
} catch(RuntimeException $ex) {
var_dump($ex->getMessage());
}
try {
uopz_set_static("phpversion", []);
} catch(RuntimeException $ex) {
var_dump($ex->getMessage());
}
try {
uopz_set_static(DateTime::class, "__construct", []);
} catch(RuntimeException $ex) {
var_dump($ex->getMessage());
}
try {
uopz_set_static(Foo::class, "nostatics", []);
} catch(RuntimeException $ex) {
var_dump($ex->getMessage());
}
try {
uopz_set_static("nostatics", []);
} catch(RuntimeException $ex) {
var_dump($ex->getMessage());
}
?>
--EXPECTF--
array(1) {
["vars"]=>
array(6) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
[4]=>
int(5)
[5]=>
int(6)
}
}
array(1) {
["vars"]=>
array(1) {
[0]=>
int(6)
}
}
string(%d) "failed to set statics in method %s::%s, it does not exist"
string(%d) "failed to set statics in function %s, it does not exist"
string(%d) "failed to set statics in internal function %s"
string(%d) "failed to set statics in internal method %s::%s"
string(%d) "failed to set statics in method %s::%s, no statics declared"
string(%d) "failed to set statics in function %s, no statics declared"
uopz-7.1.1/tests/009.phpt 0000664 0001750 0001750 00000002141 14133502033 013530 0 ustar remi remi --TEST--
uopz_set_hook
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
method(true);
class Bar extends Foo {}
try {
uopz_set_hook(Bar::class, "method", function(){});
} catch (Throwable $t) {
var_dump($t->getMessage());
}
try {
uopz_set_hook(Bar::class, "none", function(){});
} catch (Throwable $t) {
var_dump($t->getMessage());
}
var_dump(uopz_set_hook("bar", function(){
var_dump("hook");
}));
bar();
var_dump(uopz_unset_hook("bar"));
bar();
var_dump(uopz_unset_hook("none"));
uopz_set_hook("bar", function() {
throw new Exception("Ooops");
});
try {
var_dump(bar());
} catch (Exception $e) {
echo $e->getMessage(), "\n";
}
?>
--EXPECTF--
bool(true)
bool(true)
object(Foo)#2 (0) {
}
string(%d) "failed to set hook for %s::%s, the method is defined in %s"
string(%d) "failed to set hook for %s::%s, the method does not exist"
bool(true)
string(4) "hook"
bool(true)
bool(false)
Ooops
uopz-7.1.1/tests/010.phpt 0000664 0001750 0001750 00000001165 14133502033 013525 0 ustar remi remi --TEST--
uopz_get_hook
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
--EXPECT--
bool(true)
object(Closure)#1 (1) {
["parameter"]=>
array(1) {
["$arg"]=>
string(10) ""
}
}
object(Closure)#2 (0) {
}
NULL
NULL
uopz-7.1.1/tests/011.phpt 0000664 0001750 0001750 00000000615 14133502033 013525 0 ustar remi remi --TEST--
uopz_unset_hook
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
method());
uopz_unset_hook(Foo::class, "method");
var_dump($foo->method());
?>
--EXPECT--
bool(true)
bool(true)
bool(false)
bool(false)
uopz-7.1.1/tests/012.phpt 0000664 0001750 0001750 00000004637 14133502033 013536 0 ustar remi remi --TEST--
uopz_add_function
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
opcache.enable_cli=0
--FILE--
priv(true);
});
uopz_add_function(Foo::class, "PRIV", /** doc **/ function(bool $arg){
return $arg;
}, ZEND_ACC_PRIVATE);
uopz_add_function(Foo::class, "STATICFUNCTION", /** doc **/ function(){
static $a = [1,2,3];
try {
$a[] = 4;
} catch (Throwable $t) {
} finally {
return count($a) == 4;
}
}, ZEND_ACC_STATIC);
uopz_add_function(Foo::class, "__construct", function() {
var_dump("__construct");
});
uopz_add_function(Foo::class, "__destruct", function(){
var_dump("__destruct");
});
uopz_add_function(Foo::class, "__clone", function() {
var_dump("clone");
return $this;
});
uopz_add_function(Foo::class, "__tostring", function(){
return "string";
});
uopz_add_function(Foo::class, "__set", function($property, $value){
var_dump($property, $value);
});
uopz_add_function(Foo::class, "__get", function($property) {
return $property;
});
uopz_add_function(Foo::class, "__isset", function($property) {
return false;
});
uopz_add_function(Foo::class, "__unset", function($property) {
throw new Error();
});
$foo = new Foo();
var_dump((string) $foo);
$x = clone $foo;
var_dump($foo->property);
$foo->property = "value";
var_dump(isset($foo->property));
try {
unset($foo->property);
} catch (Error $ex) {
echo "unset\n";
}
var_dump($foo->method());
var_dump(Foo::staticFunction());
try {
var_dump($foo->priv(false));
} catch(Error $e) {
var_dump($e->getMessage());
}
try {
uopz_add_function(Foo::class, "exists", function() {});
} catch(Exception $e) {
var_dump($e->getMessage());
}
try {
uopz_add_function("uopz_add_function", function(){});
} catch (Exception $e) {
var_dump($e->getMessage());
}
$foo = "foo";
uopz_add_function($foo . "bar", function() {});
foobar();
?>
--EXPECTF--
string(%d) "__construct"
string(%d) "string"
string(%d) "clone"
string(%d) "property"
string(%d) "property"
string(%d) "value"
bool(false)
unset
bool(true)
bool(true)
string(%d) "Call to private method Foo::priv() from %s"
string(%d) "will not replace existing method %s::%s, use uopz_set_return instead"
string(%d) "will not replace existing function %s, use uopz_set_return instead"
string(%d) "__destruct"
string(%d) "__destruct"
uopz-7.1.1/tests/013.phpt 0000664 0001750 0001750 00000002211 14133502033 013521 0 ustar remi remi --TEST--
uopz_del_function
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
opcache.enable_cli=0
--FILE--
method());
var_dump(uopz_del_function(Foo::class, "method"));
try {
$foo->method();
} catch(Throwable $e) {
var_dump($e->getMessage());
}
try {
uopz_del_function(Foo::class, "exists");
} catch (Throwable $t) {
var_dump($t->getMessage());
}
try {
uopz_del_function("phpversion");
} catch (Throwable $t) {
var_dump($t->getMessage());
}
try {
uopz_del_function(stdClass::class, "none");
} catch (Throwable $t) {
var_dump($t->getMessage());
}
try {
uopz_del_function("none42");
} catch (Throwable $t) {
var_dump($t->getMessage());
}
?>
--EXPECTF--
bool(true)
bool(true)
bool(true)
string(%d) "Call to undefined method Foo::method()"
string(%d) "cannot delete method %s::%s, it was not added by uopz"
string(%d) "cannot delete function %s, it was not added by uopz"
string(%d) "cannot delete method %s::%s, it does not exist"
string(%d) "cannot delete function %s, it does not exist"
uopz-7.1.1/tests/016.phpt 0000664 0001750 0001750 00000002722 14133502033 013533 0 ustar remi remi --TEST--
uopz_flags
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
opcache.enable_cli=0
--FILE--
getMessage());
}
try {
uopz_flags(Foo::class, '', ZEND_ACC_STATIC);
} catch (Exception $ex) {
var_dump($ex->getMessage());
}
uopz_flags(Foo::class, '', ZEND_ACC_FINAL);
$reflector = new ReflectionClass(Foo::class);
var_dump($reflector->isFinal());
try {
uopz_flags(Foo::class, "none", ZEND_ACC_PUBLIC);
} catch (Exception $ex) {
var_dump($ex->getMessage());
}
try {
uopz_flags("none", ZEND_ACC_STATIC);
} catch (Exception $ex) {
var_dump($ex->getMessage());
}
try {
uopz_flags("", ZEND_ACC_STATIC);
} catch (Exception $ex) {
var_dump($ex->getMessage());
}
?>
--EXPECTF--
bool(false)
bool(true)
bool(false)
string(%d) "attempt to set public, private or protected on class entry %s, not allowed"
string(%d) "attempt to set static on class entry %s, not allowed"
bool(true)
string(%d) "failed to set or get flags of method %s::%s, it does not exist"
string(%d) "failed to set or get flags of function %s, it does not exist"
string(%d) "failed to set or get flags of function , it does not exist"
uopz-7.1.1/tests/017.phpt 0000664 0001750 0001750 00000001010 14133502033 013521 0 ustar remi remi --TEST--
uopz_redefine
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
--EXPECT--
int(1)
int(2)
int(3)
int(4)
int(5)
OK
uopz-7.1.1/tests/018.phpt 0000664 0001750 0001750 00000001242 14133502033 013531 0 ustar remi remi --TEST--
uopz_undefine
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
getConstants()));
var_dump(uopz_undefine(Foo::class, "NONE"));
uopz_undefine(Foo::class, "QUX");
var_dump(count($reflector->getConstants()));
try {
uopz_undefine("PHP_VERSION");
} catch (RuntimeException $ex) {
echo "OK\n";
}
?>
--EXPECT--
bool(true)
bool(false)
int(1)
int(1)
bool(false)
int(0)
OK
uopz-7.1.1/tests/019.phpt 0000664 0001750 0001750 00000003365 14133502033 013542 0 ustar remi remi --TEST--
uopz_set_property/uopz_get_property
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
--FILE--
bar;
}
}
echo "----------------------\n";
$foo = new Foo();
uopz_set_property($foo, "bar", 10);
var_dump(uopz_get_property($foo, "bar"));
echo "-----------------------\n\n";
echo "----------------------\n";
uopz_set_property(Foo::class, "staticBar", 100);
var_dump(uopz_get_property(Foo::class, "staticBar"));
var_dump($foo->testBar(), $foo->testStaticBar());
try {
uopz_set_property(Foo::class, "staticQux", 10);
} catch (RuntimeException $ex) {
var_dump($ex->getMessage());
}
echo "-----------------------\n\n";
echo "----------------------\n";
class Bar {
private static $bar;
public function foo() {
return self::$bar;
}
}
class Qux extends Bar {}
$qux = new Qux;
uopz_set_property(Qux::class, "bar", 10);
var_dump($qux->foo(), uopz_get_property(Qux::class, "bar"));
class Baz {
private $bar;
public function foo() {
return $this->bar;
}
}
class Bill extends Baz {}
$bill = new Bill;
uopz_set_property($bill, "bar", 100);
var_dump($bill->foo(), uopz_get_property($bill, "bar"));
uopz_set_property($bill, "qux", 1000);
var_dump($bill->qux, uopz_get_property($bill, "qux"));
var_dump(@uopz_get_property($bill, "none"));
echo "-----------------------\n\n";
?>
--EXPECTF--
----------------------
int(10)
-----------------------
----------------------
int(100)
int(10)
int(100)
string(%d) "cannot set non-existent static property %s::%s"
-----------------------
----------------------
int(10)
int(10)
int(100)
int(100)
int(1000)
int(1000)
NULL
-----------------------
uopz-7.1.1/tests/020.phpt 0000664 0001750 0001750 00000000535 14133502033 013526 0 ustar remi remi --TEST--
uopz_get_exit_status
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
uopz.exit=0
opcache.enable_cli=0
xdebug.enable=0
--FILE--
--EXPECT--
int(10)
int(20)
uopz-7.1.1/tests/021.phpt 0000664 0001750 0001750 00000000422 14133502033 013522 0 ustar remi remi --TEST--
uopz.disabled
--EXTENSIONS--
uopz
--INI--
uopz.disable=1
--FILE--
--EXPECTF--
Fatal error: Uncaught %s: uopz is disabled by configuration (uopz.disable) in %s:2
Stack trace:
#0 %s(2): uopz_set_return()
#1 {main}
thrown in %s on line 2
uopz-7.1.1/tests/027.phpt 0000664 0001750 0001750 00000000514 14133502033 013532 0 ustar remi remi --TEST--
init method call non string method
--EXTENSIONS--
uopz
--FILE--
$method());
?>
--EXPECTF--
Fatal error: Uncaught Error: Method name must be a string in %s:11
Stack trace:
#0 {main}
thrown in %s on line 11
uopz-7.1.1/tests/028.phpt 0000664 0001750 0001750 00000000414 14133502033 013532 0 ustar remi remi --TEST--
init method call non object object
--EXTENSIONS--
uopz
--FILE--
method());
?>
--EXPECTF--
Fatal error: Uncaught Error: Call to a member function method() on string in %s:4
Stack trace:
#0 {main}
thrown in %s on line 4
uopz-7.1.1/tests/029.phpt 0000664 0001750 0001750 00000000342 14133502033 013533 0 ustar remi remi --TEST--
init method call object ref
--EXTENSIONS--
uopz
--FILE--
method());
?>
--EXPECTF--
bool(false)
uopz-7.1.1/tests/032.phpt 0000664 0001750 0001750 00000000705 14133502033 013530 0 ustar remi remi --TEST--
init ns fcall
--EXTENSIONS--
uopz
--INI--
uopz.disable=0
opcache.enable_cli=0
--FILE--
method());
}
}
class Mock extends Test {
public static function method() {
return true;
}
}
Test::run();
--EXPECTF--
bool(true)
uopz-7.1.1/tests/035.phpt 0000664 0001750 0001750 00000000336 14133502033 013533 0 ustar remi remi --TEST--
fetch class constant non existent class
--EXTENSIONS--
uopz
--FILE--
__construct()
#1 {main}
thrown in %s on line 10
uopz-7.1.1/tests/038.phpt 0000664 0001750 0001750 00000000322 14133502033 013531 0 ustar remi remi --TEST--
fetch class string no mock
--EXTENSIONS--
uopz
--FILE--
--EXPECTF--
Fatal error: Uncaught Error: Class name must be a valid object or a string in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d
uopz-7.1.1/uopz.h 0000664 0001750 0001750 00000004000 14133502033 012323 0 ustar remi remi /*
+----------------------------------------------------------------------+
| uopz |
+----------------------------------------------------------------------+
| Copyright (c) Joe Watkins 2016-2021 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 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_01.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: Joe Watkins |
+----------------------------------------------------------------------+
*/
#ifndef UOPZ_H
#define UOPZ_H
extern zend_module_entry uopz_module_entry;
#define phpext_uopz_ptr &uopz_module_entry
#define PHP_UOPZ_VERSION "7.1.1"
#define PHP_UOPZ_EXTNAME "uopz"
ZEND_BEGIN_MODULE_GLOBALS(uopz)
zend_long copts;
HashTable returns;
HashTable mocks;
HashTable hooks;
zend_bool exit;
zval estatus;
zend_bool disable;
ZEND_END_MODULE_GLOBALS(uopz)
#ifdef ZTS
#define UOPZ(v) TSRMG(uopz_globals_id, zend_uopz_globals *, v)
#else
#define UOPZ(v) (uopz_globals.v)
#endif
#include "ext/spl/spl_exceptions.h"
#include "Zend/zend_inheritance.h"
#include "Zend/zend_exceptions.h"
#include "Zend/zend_closures.h"
#define uopz_exception(message, ...) zend_throw_exception_ex\
(spl_ce_RuntimeException, 0, message, ##__VA_ARGS__)
#endif /* UOPZ_H */
/*
* 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
*/
uopz-7.1.1/uopz.c 0000664 0001750 0001750 00000044531 14133502033 012333 0 ustar remi remi /*
+----------------------------------------------------------------------+
| uopz |
+----------------------------------------------------------------------+
| Copyright (c) Joe Watkins 2016-2021 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 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_01.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: Joe Watkins |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "uopz.h"
#include "src/util.h"
#include "src/return.h"
#include "src/hook.h"
#include "src/constant.h"
#include "src/class.h"
#include "src/function.h"
#include "src/handlers.h"
#include "src/executors.h"
ZEND_DECLARE_MODULE_GLOBALS(uopz)
#define uopz_parse_parameters(spec, ...) zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), spec, ##__VA_ARGS__)
#define uopz_refuse_parameters(message, ...) zend_throw_exception_ex\
(spl_ce_InvalidArgumentException, 0, message, ##__VA_ARGS__)
#define uopz_disabled_guard() do { \
if (UOPZ(disable)) { \
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "uopz is disabled by configuration (uopz.disable)"); \
return; \
} \
} while(0)
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("uopz.disable", "0", PHP_INI_SYSTEM, OnUpdateBool, disable, zend_uopz_globals, uopz_globals)
STD_PHP_INI_ENTRY("uopz.exit", "0", PHP_INI_SYSTEM, OnUpdateBool, exit, zend_uopz_globals, uopz_globals)
PHP_INI_END()
/* {{{ */
static void php_uopz_init_globals(zend_uopz_globals *ng) {
memset(ng, 0, sizeof(zend_uopz_globals));
} /* }}} */
/* {{{ PHP_MINIT_FUNCTION
*/
static PHP_MINIT_FUNCTION(uopz)
{
ZEND_INIT_MODULE_GLOBALS(uopz, php_uopz_init_globals, NULL);
REGISTER_INI_ENTRIES();
if (UOPZ(disable)) {
return SUCCESS;
}
REGISTER_LONG_CONSTANT("ZEND_ACC_PUBLIC", ZEND_ACC_PUBLIC, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("ZEND_ACC_PRIVATE", ZEND_ACC_PRIVATE, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("ZEND_ACC_PROTECTED", ZEND_ACC_PROTECTED, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("ZEND_ACC_PPP_MASK", ZEND_ACC_PPP_MASK, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("ZEND_ACC_STATIC", ZEND_ACC_STATIC, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("ZEND_ACC_FINAL", ZEND_ACC_FINAL, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("ZEND_ACC_ABSTRACT", ZEND_ACC_ABSTRACT, CONST_CS|CONST_PERSISTENT);
uopz_executors_init();
uopz_handlers_init();
return SUCCESS;
}
/* }}} */
/* {{{ */
static PHP_MSHUTDOWN_FUNCTION(uopz)
{
if (UOPZ(disable)) {
return SUCCESS;
}
uopz_handlers_shutdown();
uopz_executors_shutdown();
return SUCCESS;
} /* }}} */
/* {{{ PHP_RINIT_FUNCTION
*/
static PHP_RINIT_FUNCTION(uopz)
{
zend_class_entry *ce = NULL;
zend_string *spl;
#ifdef ZTS
ZEND_TSRMLS_CACHE_UPDATE();
#endif
if (UOPZ(disable)) {
return SUCCESS;
}
if (INI_INT("opcache.optimization_level")) {
zend_string *optimizer = zend_string_init(
ZEND_STRL("opcache.optimization_level"), 1);
zend_long level = INI_INT("opcache.optimization_level");
zend_string *value;
/* must disable block pass 1 constant substitution */
level &= ~(1<<0);
/* disable CFG optimization (exit optimized away here) */
level &= ~(1<<4);
/* disable DCE (want code after exit) */
level &= ~(1<<13);
/* don't inline functions */
level &= ~(1<<15);
value = strpprintf(0, "0x%08X", (unsigned int) level);
zend_alter_ini_entry(optimizer, value,
ZEND_INI_SYSTEM, ZEND_INI_STAGE_ACTIVATE);
zend_string_release(optimizer);
zend_string_release(value);
}
spl = zend_string_init(ZEND_STRL("RuntimeException"), 0);
spl_ce_RuntimeException =
(ce = zend_lookup_class(spl)) ?
ce : zend_exception_get_default();
zend_string_release(spl);
spl = zend_string_init(ZEND_STRL("InvalidArgumentException"), 0);
spl_ce_InvalidArgumentException =
(ce = zend_lookup_class(spl)) ?
ce : zend_exception_get_default();
zend_string_release(spl);
uopz_request_init();
return SUCCESS;
} /* }}} */
/* {{{ PHP_RSHUTDOWN_FUNCTION
*/
static PHP_RSHUTDOWN_FUNCTION(uopz)
{
if (UOPZ(disable)) {
return SUCCESS;
}
uopz_request_shutdown();
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION
*/
static PHP_MINFO_FUNCTION(uopz)
{
php_info_print_table_start();
php_info_print_table_header(2, "uopz support", UOPZ(disable) ? "disabled" : "enabled");
php_info_print_table_row(2, "Version", PHP_UOPZ_VERSION);
php_info_print_table_end();
DISPLAY_INI_ENTRIES();
}
/* }}} */
/* {{{ proto bool uopz_set_return(string class, string function, mixed variable [, bool execute ])
proto bool uopz_set_return(function, mixed variable [, bool execute ]) */
static PHP_FUNCTION(uopz_set_return)
{
zend_string *function = NULL;
zval *variable = NULL;
zend_class_entry *clazz = NULL;
zend_bool execute = 0;
uopz_disabled_guard();
if (uopz_parse_parameters("CSz|b", &clazz, &function, &variable, &execute) != SUCCESS &&
uopz_parse_parameters("Sz|b", &function, &variable, &execute) != SUCCESS) {
uopz_refuse_parameters(
"unexpected parameter combination, expected (class, function, variable [, execute]) or (function, variable [, execute])");
return;
}
if (execute && (Z_TYPE_P(variable) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(variable), zend_ce_closure))) {
uopz_refuse_parameters(
"only closures are accepted as executable return values");
return;
}
if (uopz_is_magic_method(clazz, function)) {
uopz_refuse_parameters(
"will not override magic methods, too magical");
return;
}
RETURN_BOOL(uopz_set_return(clazz, function, variable, execute));
} /* }}} */
/* {{{ proto bool uopz_unset_return(string class, string function)
proto bool uopz_unset_return(string function) */
static PHP_FUNCTION(uopz_unset_return)
{
zend_string *function = NULL;
zend_class_entry *clazz = NULL;
uopz_disabled_guard();
if (uopz_parse_parameters("CS", &clazz, &function) != SUCCESS &&
uopz_parse_parameters("S", &function) != SUCCESS) {
uopz_refuse_parameters(
"unexpected parameter combination, expected (class, function) or (function)");
return;
}
RETURN_BOOL(uopz_unset_return(clazz, function));
} /* }}} */
/* {{{ proto mixed uopz_get_return(string class, string function)
proto mixed uopz_get_return(string function) */
static PHP_FUNCTION(uopz_get_return)
{
zend_string *function = NULL;
zend_class_entry *clazz = NULL;
uopz_disabled_guard();
if (uopz_parse_parameters("CS", &clazz, &function) != SUCCESS &&
uopz_parse_parameters("S", &function) != SUCCESS) {
uopz_refuse_parameters(
"unexpected parameter combination, expected (class, function)");
return;
}
uopz_get_return(clazz, function, return_value);
} /* }}} */
/* {{{ proto void uopz_set_mock(string class, mixed mock) */
static PHP_FUNCTION(uopz_set_mock)
{
zend_string *clazz;
zval *mock;
uopz_disabled_guard();
if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz", &clazz, &mock) != SUCCESS) {
RETURN_THROWS();
}
if (Z_TYPE_P(mock) != IS_STRING && Z_TYPE_P(mock) != IS_OBJECT) {
uopz_refuse_parameters(
"unexpected parameter combination, mock is expected to be a string, or an object");
return;
}
uopz_set_mock(clazz, mock);
} /* }}} */
/* {{{ proto void uopz_unset_mock(string mock) */
static PHP_FUNCTION(uopz_unset_mock)
{
zend_string *clazz;
uopz_disabled_guard();
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &clazz) != SUCCESS) {
RETURN_THROWS();
}
uopz_unset_mock(clazz);
} /* }}} */
/* {{{ proto void uopz_get_mock(string mock) */
static PHP_FUNCTION(uopz_get_mock)
{
zend_string *clazz;
uopz_disabled_guard();
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &clazz) != SUCCESS) {
RETURN_THROWS();
}
uopz_get_mock(clazz, return_value);
} /* }}} */
/* {{{ proto array uopz_get_static(string class, string method)
array uopz_get_static(string function) */
static PHP_FUNCTION(uopz_get_static)
{
zend_string *function = NULL;
zend_class_entry *clazz = NULL;
uopz_disabled_guard();
if (uopz_parse_parameters("CS", &clazz, &function) != SUCCESS &&
uopz_parse_parameters("S", &function) != SUCCESS) {
uopz_refuse_parameters(
"unexpected parameter combination, expected (class, function) or (function)");
return;
}
uopz_get_static(clazz, function, return_value);
} /* }}} */
/* {{{ proto array uopz_set_static(string class, string method, array statics)
array uopz_set_static(string function, array statics) */
static PHP_FUNCTION(uopz_set_static)
{
zend_string *function = NULL;
zend_class_entry *clazz = NULL;
zval *statics = NULL;
uopz_disabled_guard();
if (uopz_parse_parameters("CSz", &clazz, &function, &statics) != SUCCESS &&
uopz_parse_parameters("Sz", &function, &statics) != SUCCESS) {
uopz_refuse_parameters(
"unexpected parameter combination, expected (class, function, statics) or (function, statics)");
return;
}
uopz_set_static(clazz, function, statics);
} /* }}} */
/* {{{ proto bool uopz_set_hook(string class, string function, Closure hook)
bool uopz_set_hook(string function, Closure hook) */
static PHP_FUNCTION(uopz_set_hook)
{
zend_string *function = NULL;
zend_class_entry *clazz = NULL;
zval *hook = NULL;
uopz_disabled_guard();
if (uopz_parse_parameters("CSO", &clazz, &function, &hook, zend_ce_closure) != SUCCESS &&
uopz_parse_parameters("SO", &function, &hook, zend_ce_closure) != SUCCESS) {
uopz_refuse_parameters(
"unexpected parameter combination, expected (class, function, hook) or (function, hook)");
return;
}
RETURN_BOOL(uopz_set_hook(clazz, function, hook));
} /* }}} */
/* {{{ proto bool uopz_unset_hook(string class, string function)
bool uopz_unset_hook(string function) */
static PHP_FUNCTION(uopz_unset_hook)
{
zend_string *function = NULL;
zend_class_entry *clazz = NULL;
uopz_disabled_guard();
if (uopz_parse_parameters("CS", &clazz, &function) != SUCCESS &&
uopz_parse_parameters("S", &function) != SUCCESS) {
uopz_refuse_parameters(
"unexpected parameter combination, expected (class, function) or (function)");
return;
}
RETURN_BOOL(uopz_unset_hook(clazz, function));
} /* }}} */
/* {{{ proto Closure uopz_get_hook(string class, string function)
Closure uopz_get_hook(string function) */
static PHP_FUNCTION(uopz_get_hook)
{
zend_string *function = NULL;
zend_class_entry *clazz = NULL;
uopz_disabled_guard();
if (uopz_parse_parameters("CS", &clazz, &function) != SUCCESS &&
uopz_parse_parameters("S", &function) != SUCCESS) {
uopz_refuse_parameters(
"unexpected parameter combination, expected (class, function) or (function)");
return;
}
uopz_get_hook(clazz, function, return_value);
} /* }}} */
/* {{{ proto bool uopz_add_function(string class, string method, Closure function [, int flags = ZEND_ACC_PUBLIC [, bool all = false]])
bool uopz_add_function(string function, Closure function [, int flags = ZEND_ACC_PUBLIC]) */
static PHP_FUNCTION(uopz_add_function)
{
zend_class_entry *clazz = NULL;
zend_string *name = NULL;
zval *closure = NULL;
zend_long flags = ZEND_ACC_PUBLIC;
zend_bool all = 1;
uopz_disabled_guard();
if (uopz_parse_parameters("CSO|lb", &clazz, &name, &closure, zend_ce_closure, &flags, &all) != SUCCESS &&
uopz_parse_parameters("SO|l", &name, &closure, zend_ce_closure, &flags) != SUCCESS) {
uopz_refuse_parameters(
"unexpected parameter combination, expected (class, function, closure [, flags]) or (function, closure [, flags])");
return;
}
RETURN_BOOL(uopz_add_function(clazz, name, closure, flags, all));
} /* }}} */
/* {{{ proto bool uopz_del_function(string class, string method [, bool all = false])
bool uopz_del_function(string function) */
static PHP_FUNCTION(uopz_del_function)
{
zend_class_entry *clazz = NULL;
zend_string *name = NULL;
zend_bool all = 1;
uopz_disabled_guard();
if (uopz_parse_parameters("CS|b", &clazz, &name, &all) != SUCCESS &&
uopz_parse_parameters("S", &name) != SUCCESS) {
uopz_refuse_parameters(
"unexpected parameter combination, expected (class, function) or (function)");
return;
}
RETURN_BOOL(uopz_del_function(clazz, name, all));
} /* }}} */
/* {{{ proto bool uopz_redefine(string constant, mixed variable)
proto bool uopz_redefine(string class, string constant, mixed variable) */
static PHP_FUNCTION(uopz_redefine)
{
zend_string *name = NULL;
zval *variable = NULL;
zend_class_entry *clazz = NULL;
uopz_disabled_guard();
if (uopz_parse_parameters("CSz", &clazz, &name, &variable) != SUCCESS &&
uopz_parse_parameters("Sz", &name, &variable) != SUCCESS) {
uopz_refuse_parameters(
"unexpected parameter combination, expected (class, constant, variable) or (constant, variable)");
return;
}
if (uopz_constant_redefine(clazz, name, variable)) {
if (clazz) {
while ((clazz = clazz->parent)) {
uopz_constant_redefine(
clazz, name, variable);
}
}
RETURN_TRUE;
} else {
RETURN_FALSE;
}
} /* }}} */
/* {{{ proto bool uopz_undefine(string constant)
proto bool uopz_undefine(string class, string constant) */
static PHP_FUNCTION(uopz_undefine)
{
zend_string *name = NULL;
zend_class_entry *clazz = NULL;
uopz_disabled_guard();
if (uopz_parse_parameters("CS", &clazz, &name) != SUCCESS &&
uopz_parse_parameters("S", &name) != SUCCESS) {
uopz_refuse_parameters(
"unexpected parameter combination, expected (class, constant) or (constant)");
return;
}
if (uopz_constant_undefine(clazz, name)) {
if (clazz) {
while ((clazz = clazz->parent)) {
uopz_constant_undefine(clazz, name);
}
}
RETURN_TRUE;
} else {
RETURN_FALSE;
}
} /* }}} */
/* {{{ proto int uopz_flags(string function [, int flags])
proto int uopz_flags(string class, string function [, int flags]) */
static PHP_FUNCTION(uopz_flags)
{
zend_string *name = NULL;
zend_class_entry *clazz = NULL;
zend_long flags = ZEND_LONG_MAX;
uopz_disabled_guard();
if (uopz_parse_parameters("CS|l", &clazz, &name, &flags) != SUCCESS &&
uopz_parse_parameters("S|l", &name, &flags) != SUCCESS) {
uopz_refuse_parameters(
"unexpected parameter combination, expected "
"(class, function, flags) or (function, flags)");
return;
}
uopz_flags(clazz, name, flags, return_value);
} /* }}} */
/* {{{ proto void uopz_set_property(object instance, string property, mixed value)
void uopz_set_property(string class, string property, mixed value) */
static PHP_FUNCTION(uopz_set_property)
{
zval *scope;
zend_string *prop;
zval *value;
uopz_disabled_guard();
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zSz", &scope, &prop, &value) != SUCCESS) {
RETURN_THROWS();
}
if (Z_TYPE_P(scope) != IS_OBJECT && Z_TYPE_P(scope) != IS_STRING) {
uopz_refuse_parameters(
"unexpected paramter combination, expected "
"(class, property, value) or (object, property, value)");
return;
}
if (Z_TYPE_P(scope) == IS_OBJECT) {
uopz_set_property(scope, prop, value);
} else {
zend_class_entry *ce = zend_lookup_class(Z_STR_P(scope));
if (!ce) {
return;
}
uopz_set_static_property(ce, prop, value);
}
} /* }}} */
/* {{{ proto mixed uopz_get_property(object instance, string property)
proto mixed uopz_get_property(string class, string property) */
static PHP_FUNCTION(uopz_get_property) {
zval *scope;
zend_string *prop;
uopz_disabled_guard();
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zS", &scope, &prop) != SUCCESS) {
RETURN_THROWS();
}
if (Z_TYPE_P(scope) != IS_OBJECT && Z_TYPE_P(scope) != IS_STRING) {
uopz_refuse_parameters(
"unexpected paramter combination, expected "
"(class, property) or (object, property)");
return;
}
if (Z_TYPE_P(scope) == IS_OBJECT) {
uopz_get_property(scope, prop, return_value);
} else {
zend_class_entry *ce = zend_lookup_class(Z_STR_P(scope));
if (!ce) {
return;
}
uopz_get_static_property(ce, prop, return_value);
}
} /* }}} */
/* {{{ proto mixed uopz_get_exit_status(void) */
static PHP_FUNCTION(uopz_get_exit_status) {
uopz_disabled_guard();
if (zend_parse_parameters_none() != SUCCESS) {
RETURN_THROWS();
}
if (Z_TYPE(UOPZ(estatus)) != IS_UNDEF) {
ZVAL_COPY(return_value, &UOPZ(estatus));
}
} /* }}} */
/* {{{ proto mixed uopz_allow_exit(bool allow) */
static PHP_FUNCTION(uopz_allow_exit) {
zend_bool allow;
uopz_disabled_guard();
if (zend_parse_parameters(ZEND_NUM_ARGS(), "b", &allow) != SUCCESS) {
RETURN_THROWS();
}
UOPZ(exit) = allow;
} /* }}} */
/* {{{ uopz_functions[]
*/
ZEND_BEGIN_ARG_INFO(uopz_ignore_arginfo, 1)
ZEND_ARG_VARIADIC_INFO(0, arguments)
ZEND_END_ARG_INFO()
# define UOPZ_FE(f) PHP_FE(f, uopz_ignore_arginfo)
ZEND_BEGIN_ARG_INFO(uopz_no_args_arginfo, 0)
ZEND_END_ARG_INFO()
# define UOPZ_FE_NOARGS(f) PHP_FE(f, uopz_no_args_arginfo)
static const zend_function_entry uopz_functions[] = {
UOPZ_FE(uopz_set_return)
UOPZ_FE(uopz_get_return)
UOPZ_FE(uopz_unset_return)
UOPZ_FE(uopz_set_mock)
UOPZ_FE(uopz_get_mock)
UOPZ_FE(uopz_unset_mock)
UOPZ_FE(uopz_get_static)
UOPZ_FE(uopz_set_static)
UOPZ_FE(uopz_set_hook)
UOPZ_FE(uopz_get_hook)
UOPZ_FE(uopz_unset_hook)
UOPZ_FE(uopz_add_function)
UOPZ_FE(uopz_del_function)
UOPZ_FE(uopz_flags)
UOPZ_FE(uopz_redefine)
UOPZ_FE(uopz_undefine)
UOPZ_FE(uopz_set_property)
UOPZ_FE(uopz_get_property)
UOPZ_FE_NOARGS(uopz_get_exit_status)
UOPZ_FE(uopz_allow_exit)
UOPZ_FE(uopz_call_user_func)
UOPZ_FE(uopz_call_user_func_array)
ZEND_FE_END
};
#undef UOPZ_FE
/* }}} */
/* {{{ uopz_module_entry
*/
zend_module_entry uopz_module_entry = {
STANDARD_MODULE_HEADER,
PHP_UOPZ_EXTNAME,
uopz_functions,
PHP_MINIT(uopz),
PHP_MSHUTDOWN(uopz),
PHP_RINIT(uopz),
PHP_RSHUTDOWN(uopz),
PHP_MINFO(uopz),
PHP_UOPZ_VERSION,
STANDARD_MODULE_PROPERTIES
};
/* }}} */
#ifdef COMPILE_DL_UOPZ
ZEND_GET_MODULE(uopz)
#ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE();
#endif
#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
*/
uopz-7.1.1/config.m4 0000664 0001750 0001750 00000002062 14133502033 012672 0 ustar remi remi PHP_ARG_ENABLE(uopz, whether to enable uopz support,
[ --enable-uopz Enable uopz support])
PHP_ARG_ENABLE(uopz-coverage, whether to enable uopz coverage support,
[ --enable-uopz-coverage Enable uopz coverage support], no, no)
PHP_ARG_WITH(uopz-sanitize, whether to enable AddressSanitizer for uopz,
[ --with-uopz-sanitize Build uopz with AddressSanitizer support], no, no)
if test "$PHP_UOPZ" != "no"; then
if test "$PHP_UOPZ_SANITIZE" != "no"; then
EXTRA_LDFLAGS="-lasan"
EXTRA_CFLAGS="-fsanitize=address -fno-omit-frame-pointer"
PHP_SUBST(EXTRA_LDFLAGS)
PHP_SUBST(EXTRA_CFLAGS)
fi
PHP_NEW_EXTENSION(uopz, uopz.c src/util.c src/return.c src/hook.c src/constant.c src/function.c src/class.c src/handlers.c src/executors.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
PHP_ADD_BUILD_DIR($ext_builddir/src, 1)
PHP_ADD_INCLUDE($ext_builddir)
AC_MSG_CHECKING([uopz coverage])
if test "$PHP_UOPZ_COVERAGE" != "no"; then
AC_MSG_RESULT([enabled])
PHP_ADD_MAKEFILE_FRAGMENT
else
AC_MSG_RESULT([disabled])
fi
fi
uopz-7.1.1/config.w32 0000664 0001750 0001750 00000000536 14133502033 012771 0 ustar remi remi // $Id$
// vim:ft=javascript
ARG_ENABLE("uopz", "for uopz support", "no");
if (PHP_UOPZ != "no") {
EXTENSION("uopz", "uopz.c");
ADD_SOURCES(
configure_module_dirname + "/src",
"util.c return.c hook.c constant.c function.c class.c handlers.c executors.c",
"uopz"
);
ADD_FLAG("CFLAGS_UOPZ", "/I" + configure_module_dirname + "");
}
uopz-7.1.1/LICENSE 0000664 0001750 0001750 00000006147 14133502033 012200 0 ustar remi remi --------------------------------------------------------------------
The PHP License, version 3.01
Copyright (c) 2012-2014 Joe Watkins. All rights reserved.
--------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
modification, is permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
3. The name "PHP" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact group@php.net.
4. Products derived from this software may not be called "PHP", nor
may "PHP" appear in their name, without prior written permission
from group@php.net. You may indicate that your software works in
conjunction with PHP by saying "Foo for PHP" instead of calling
it "PHP Foo" or "phpfoo"
5. The PHP Group may publish revised and/or new versions of the
license from time to time. Each version will be given a
distinguishing version number.
Once covered code has been published under a particular version
of the license, you may always continue to use it under the terms
of that version. You may also choose to use such covered code
under the terms of any subsequent version of the license
published by the PHP Group. No one other than the PHP Group has
the right to modify the terms applicable to covered code created
under this License.
6. Redistributions of any form whatsoever must retain the following
acknowledgment:
"This product includes PHP software, freely available from
".
THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------
The PHP Group can be contacted via Email at group@php.net.
For more information on the PHP Group and the PHP project,
please see .
PHP includes the Zend Engine, freely available at
.
uopz-7.1.1/README.md 0000664 0001750 0001750 00000017010 14133502033 012441 0 ustar remi remi UOPZ
====
*User Operations for Zend*
[](https://github.com/krakjoe/uopz/actions/workflows/ci.yml)
[](https://coveralls.io/github/krakjoe/uopz?branch=master)
The ```uopz``` extension is focused on providing utilities to aid with unit testing PHP code.
It supports the following activities:
- Intercepting function execution
- Intercepting object creation
- Hooking into function execution
- Manipulation of function statics
- Manipulation of function flags
- Redefinition of constants
- Deletion of constants
- Runtime creation of functions and methods
*Note: All of the above activities are compatible with opcache*
Requirements and Installation
=============================
If you use XDebug you need to use version 2.9.4 or higher.
See [INSTALL.md](INSTALL.md)
API
===
*The PHP API for ```uopz```*
```php
/**
* Provide a return value for an existing function
* @param string class
* @param string function
* @param mixed value
* @param bool execute
* If value is a Closure and execute flag is set, the Closure will
* be executed in place of the existing function
**/
function uopz_set_return(string class, string function, mixed value [, bool execute = 0]) : bool;
/**
* Provide a return value for an existing function
* @param string function
* @param mixed value
* @param bool execute
* If value is a Closure and execute flag is set, the Closure will
* be executed in place of the existing function
**/
function uopz_set_return(string function, mixed value [, bool execute = 0]) : bool;
/**
* Get a previously set return value
* @param string class
* @param string function
**/
function uopz_get_return(string class, string function) : mixed;
/**
* Get a previously set return value
* @param string function
**/
function uopz_get_return(string function) : mixed;
/**
* Unset a previously set return value
* @param string class
* @param string function
**/
function uopz_unset_return(string class, string function) : bool;
/**
* Unset a previously set return value
* @param string function
**/
function uopz_unset_return(string function) : bool;
/**
* Use mock in place of class
* @param string class
* @param mixed mock
* Mock can be an object, or the name of a class
**/
function uopz_set_mock(string class, mixed mock);
/**
* Get previously set mock for class
* @param string class
**/
function uopz_get_mock(string class);
/**
* Unset previously set mock
* @param string class
**/
function uopz_unset_mock(string class);
/**
* Get static variables from method scope
* @param string class
* @param string function
**/
function uopz_get_static(string class, string function) : array;
/**
* Get static variables from function scope
* @param string function
**/
function uopz_get_static(string function) : array;
/**
* Set static variables in method scope
* @param string class
* @param string function
* @param array static
**/
function uopz_set_static(string class, string function, array static);
/**
* Set static variables in function scope
* @param string function
* @param array static
**/
function uopz_set_static(string function, array static);
/**
* Execute hook when entering class::function
* @param string class
* @param string function
**/
function uopz_set_hook(string class, string function, Closure hook) : bool;
/**
* Execute hook when entering function
* @param string function
**/
function uopz_set_hook(string function, Closure hook) : bool;
/**
* Get previously set hook on class::function
* @param string class
* @param string function
**/
function uopz_get_hook(string class, string function) : Closure;
/**
* Get previously set hook on function
* @param string function
**/
function uopz_get_hook(string function) : Closure;
/**
* Remove previously set hook on class::function
* @param string class
* @param string function
**/
function uopz_unset_hook(string class, string function) : bool;
/**
* Remove previously set hook on function
* @param string function
**/
function uopz_unset_hook(string function) : bool;
/**
* Add a non-existent method
* @param string class
* @param string function
* @param Closure handler
* @param int flags
* @param bool all
* If all is true, all classes that descend from class will also be affected
**/
function uopz_add_function(string class, string function, Closure handler [, int flags = ZEND_ACC_PUBLIC [, bool all = true]]) : bool;
/**
* Add a non-existent function
* @param string function
* @param Closure handler
* @param int flags
* @param bool all
* If all is true, all classes that descend from class will also be affected
**/
function uopz_add_function(string function, Closure handler [, int flags = ZEND_ACC_PUBLIC [, bool all = true]]) : bool;
/**
* Delete a previously added method
* @param string class
* @param string function
* @param bool all
* If all is true, all classes that descend from class will also be affected
**/
function uopz_del_function(string class, string function, [, bool all = true]);
/**
* Delete a previously added function
* @param string function
**/
function uopz_del_function(string function);
/**
* Redefine $class::$constant to $value
* @param string class
* @param string constant
* @param mixed value
* Note: only user constants should be redefined
* Note: if the constant does not exist it will be created
**/
function uopz_redefine(string class, string constant, mixed value);
/**
* Redefine $constant to $value
* @param string constant
* @param mixed value
* Note: only user constants should be redefined
* Note: if the constant does not exist it will be created
**/
function uopz_redefine(string constant, mixed value);
/**
* Delete $class::$constant
* @param string class
* @param string constant
* Note: only user constants should be undefined
**/
function uopz_undefine(string class, string constant);
/**
* Delete $constant
* @param string constant
* Note: only user constants should be undefined
**/
function uopz_undefine(string constant);
/**
* Get or set flags on $class::$method()
* @param string class
* @param string method
* @param int flags
*/
function uopz_flags(string class, string method [, int flags]) : int;
/**
* Get or set flags on $method()
* @param string method
* @param int flags
*/
function uopz_flags(string function, [, int flags]) : int;
/**
* Set instance property
* @param object instance
* @param string property
* @param mixed value
*/
function uopz_set_property(object instance, string property, mixed value);
/**
* Set static class property
* @param string class
* @param string property
* @param mixed value
*/
function uopz_set_property(string class, string property, mixed value);
/**
* Get instance property
* @param object instance
* @param string property
*/
function uopz_get_property(object instance, string property) : mixed;
/**
* Get static class property
* @param string class
* @param string property
*/
function uopz_get_property(string class, string property) : mixed;
/**
* Retrieve the last set exit() status
* Note: opcache optimizes away dead code after unconditional exit
* Note: exit() breaks xdebug hooks
*/
function uopz_get_exit_status() : mixed;
/**
* Allows control over disabled exit opcode
* @param bool allow
* Note: by default exit will be ignored
*/
function uopz_allow_exit(bool allow) : void;
```
Supported Versions
==================
The currently supported version of uopz is 7 which requires PHP8.0+
Testing
=======
*Running the test suite*
After ``make`` has executed, run:
make test
You are done reading
====================
That is all !!!