mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
ext/pcre: Refactor preg_replace_callback(_array)() to not pass a useless FCI (#17365)
* ext/pcre: Refactor php_pcre_replace_func_impl() to not rely on an FCI * ext/pcre: Refactor populate_subpat_array() to take subject as a HashTable* This makes the assumption the zval is always an array explicit * ext/pcre: Refactor php_pcre_replace_func_impl() We don't need the FCI any more, and we always have the subject as a zend_string. * ext/pcre: Refactor php_pcre_replace_func() We don't need the FCI any more * ext/pcre: Refactor php_replace_in_subject_func() We don't need the FCI any more Make the Hashtable param const Throw exception on non string entries * ext/pcre: Refactor preg_replace_func_impl() We don't need the FCI anymore Make the Hashtable params const Rename function to indicate it is a PHP pcre function * ext/pcre: Add trampoline tests for preg_replace_callback(_array)() * ext/pcre: Handle trampolines properly for preg_replace_callback(_array)() * Revert FCI passing removal
This commit is contained in:
committed by
GitHub
parent
cee64ed3bd
commit
d6cc31cf95
@@ -1032,13 +1032,12 @@ static inline void add_offset_pair(
|
||||
/* }}} */
|
||||
|
||||
static void populate_subpat_array(
|
||||
zval *subpats, const char *subject, PCRE2_SIZE *offsets, zend_string **subpat_names,
|
||||
HashTable *subpats_ht, const char *subject, PCRE2_SIZE *offsets, zend_string **subpat_names,
|
||||
uint32_t num_subpats, int count, const PCRE2_SPTR mark, zend_long flags) {
|
||||
zend_long offset_capture = flags & PREG_OFFSET_CAPTURE;
|
||||
zend_long unmatched_as_null = flags & PREG_UNMATCHED_AS_NULL;
|
||||
zval val;
|
||||
int i;
|
||||
HashTable *subpats_ht = Z_ARRVAL_P(subpats);
|
||||
if (subpat_names) {
|
||||
if (offset_capture) {
|
||||
for (i = 0; i < count; i++) {
|
||||
@@ -1088,15 +1087,17 @@ static void populate_subpat_array(
|
||||
zend_hash_next_index_insert_new(subpats_ht, &val);
|
||||
}
|
||||
if (unmatched_as_null) {
|
||||
ZVAL_NULL(&val);
|
||||
for (i = count; i < num_subpats; i++) {
|
||||
add_next_index_null(subpats);
|
||||
zend_hash_next_index_insert_new(subpats_ht, &val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Add MARK, if available */
|
||||
if (mark) {
|
||||
add_assoc_string_ex(subpats, "MARK", sizeof("MARK") - 1, (char *)mark);
|
||||
ZVAL_STRING(&val, (char *)mark);
|
||||
zend_hash_str_add_new(subpats_ht, ZEND_STRL("MARK"), &val);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1353,7 +1354,7 @@ matched:
|
||||
mark = pcre2_get_mark(match_data);
|
||||
array_init_size(&result_set, count + (mark ? 1 : 0));
|
||||
populate_subpat_array(
|
||||
&result_set, subject, offsets, subpat_names,
|
||||
Z_ARRVAL(result_set), subject, offsets, subpat_names,
|
||||
num_subpats, count, mark, flags);
|
||||
/* And add it to the output array */
|
||||
zend_hash_next_index_insert_new(Z_ARRVAL_P(subpats), &result_set);
|
||||
@@ -1362,7 +1363,7 @@ matched:
|
||||
/* For each subpattern, insert it into the subpatterns array. */
|
||||
mark = pcre2_get_mark(match_data);
|
||||
populate_subpat_array(
|
||||
subpats, subject, offsets, subpat_names, num_subpats, count, mark, flags);
|
||||
Z_ARRVAL_P(subpats), subject, offsets, subpat_names, num_subpats, count, mark, flags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1547,40 +1548,29 @@ static int preg_get_backref(char **str, int *backref)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ preg_do_repl_func */
|
||||
/* Return NULL if an exception has occurred */
|
||||
static zend_string *preg_do_repl_func(zend_fcall_info *fci, zend_fcall_info_cache *fcc, const char *subject, PCRE2_SIZE *offsets, zend_string **subpat_names, uint32_t num_subpats, int count, const PCRE2_SPTR mark, zend_long flags)
|
||||
{
|
||||
zend_string *result_str;
|
||||
zend_string *result_str = NULL;
|
||||
zval retval; /* Function return value */
|
||||
zval arg; /* Argument to pass to function */
|
||||
|
||||
array_init_size(&arg, count + (mark ? 1 : 0));
|
||||
populate_subpat_array(&arg, subject, offsets, subpat_names, num_subpats, count, mark, flags);
|
||||
populate_subpat_array(Z_ARRVAL(arg), subject, offsets, subpat_names, num_subpats, count, mark, flags);
|
||||
|
||||
fci->retval = &retval;
|
||||
fci->param_count = 1;
|
||||
fci->params = &arg;
|
||||
|
||||
if (zend_call_function(fci, fcc) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
|
||||
if (EXPECTED(Z_TYPE(retval) == IS_STRING)) {
|
||||
result_str = Z_STR(retval);
|
||||
} else {
|
||||
result_str = zval_get_string_func(&retval);
|
||||
zval_ptr_dtor(&retval);
|
||||
}
|
||||
} else {
|
||||
if (!EG(exception)) {
|
||||
php_error_docref(NULL, E_WARNING, "Unable to call custom replacement function");
|
||||
}
|
||||
|
||||
result_str = zend_string_init(&subject[offsets[0]], offsets[1] - offsets[0], 0);
|
||||
}
|
||||
|
||||
zend_call_function(fci, fcc);
|
||||
zval_ptr_dtor(&arg);
|
||||
/* No Exception has occurred */
|
||||
if (EXPECTED(Z_TYPE(retval) != IS_UNDEF)) {
|
||||
result_str = zval_try_get_string(&retval);
|
||||
}
|
||||
zval_ptr_dtor(&retval);
|
||||
|
||||
return result_str;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_pcre_replace */
|
||||
PHPAPI zend_string *php_pcre_replace(zend_string *regex,
|
||||
@@ -1851,14 +1841,14 @@ error:
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_pcre_replace_func_impl() */
|
||||
static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_string *subject_str, const char *subject, size_t subject_len, zend_fcall_info *fci, zend_fcall_info_cache *fcc, size_t limit, size_t *replace_count, zend_long flags)
|
||||
{
|
||||
static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_string *subject_str,
|
||||
zend_fcall_info *fci, zend_fcall_info_cache *fcc,
|
||||
size_t limit, size_t *replace_count, zend_long flags
|
||||
) {
|
||||
uint32_t options; /* Execution options */
|
||||
int count; /* Count of matched subpatterns */
|
||||
zend_string **subpat_names; /* Array for named subpatterns */
|
||||
uint32_t num_subpats; /* Number of captured subpatterns */
|
||||
size_t new_len; /* Length of needed storage */
|
||||
size_t alloc_len; /* Actual allocated length */
|
||||
PCRE2_SIZE start_offset; /* Where the new search starts */
|
||||
size_t last_end_offset; /* Where the last search ended */
|
||||
@@ -1866,7 +1856,6 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin
|
||||
*piece; /* The current piece of subject */
|
||||
size_t result_len; /* Length of result */
|
||||
zend_string *result; /* Result of replacement */
|
||||
zend_string *eval_result; /* Result of custom function */
|
||||
pcre2_match_data *match_data;
|
||||
bool old_mdata_used;
|
||||
|
||||
@@ -1912,15 +1901,15 @@ static zend_string *php_pcre_replace_func_impl(pcre_cache_entry *pce, zend_strin
|
||||
/* Execute the regular expression. */
|
||||
#ifdef HAVE_PCRE_JIT_SUPPORT
|
||||
if ((pce->preg_options & PREG_JIT) && options) {
|
||||
count = pcre2_jit_match(pce->re, (PCRE2_SPTR)subject, subject_len, start_offset,
|
||||
count = pcre2_jit_match(pce->re, (PCRE2_SPTR)ZSTR_VAL(subject_str), ZSTR_LEN(subject_str), start_offset,
|
||||
PCRE2_NO_UTF_CHECK, match_data, mctx);
|
||||
} else
|
||||
#endif
|
||||
count = pcre2_match(pce->re, (PCRE2_SPTR)subject, subject_len, start_offset,
|
||||
count = pcre2_match(pce->re, (PCRE2_SPTR)ZSTR_VAL(subject_str), ZSTR_LEN(subject_str), start_offset,
|
||||
options, match_data, mctx);
|
||||
|
||||
while (1) {
|
||||
piece = subject + last_end_offset;
|
||||
piece = ZSTR_VAL(subject_str) + last_end_offset;
|
||||
|
||||
if (count >= 0 && limit) {
|
||||
/* Check for too many substrings condition. */
|
||||
@@ -1944,16 +1933,19 @@ matched:
|
||||
}
|
||||
|
||||
/* Set the match location in subject */
|
||||
match = subject + offsets[0];
|
||||
match = ZSTR_VAL(subject_str) + offsets[0];
|
||||
|
||||
new_len = result_len + offsets[0] - last_end_offset; /* part before the match */
|
||||
/* Length of needed storage */
|
||||
size_t new_len = result_len + offsets[0] - last_end_offset; /* part before the match */
|
||||
|
||||
/* Use custom function to get replacement string and its length. */
|
||||
eval_result = preg_do_repl_func(
|
||||
fci, fcc, subject, offsets, subpat_names, num_subpats, count,
|
||||
zend_string *eval_result = preg_do_repl_func(
|
||||
fci, fcc, ZSTR_VAL(subject_str), offsets, subpat_names, num_subpats, count,
|
||||
pcre2_get_mark(match_data), flags);
|
||||
|
||||
ZEND_ASSERT(eval_result);
|
||||
if (UNEXPECTED(eval_result == NULL)) {
|
||||
goto error;
|
||||
}
|
||||
new_len = zend_safe_address_guarded(1, ZSTR_LEN(eval_result) + ZSTR_MAX_OVERHEAD, new_len) -ZSTR_MAX_OVERHEAD;
|
||||
if (new_len >= alloc_len) {
|
||||
alloc_len = zend_safe_address_guarded(2, new_len, ZSTR_MAX_OVERHEAD) - ZSTR_MAX_OVERHEAD;
|
||||
@@ -1985,10 +1977,10 @@ matched:
|
||||
the match again at the same point. If this fails (picked up above) we
|
||||
advance to the next character. */
|
||||
if (start_offset == offsets[0]) {
|
||||
count = pcre2_match(pce->re, (PCRE2_SPTR)subject, subject_len, start_offset,
|
||||
count = pcre2_match(pce->re, (PCRE2_SPTR)ZSTR_VAL(subject_str), ZSTR_LEN(subject_str), start_offset,
|
||||
PCRE2_NO_UTF_CHECK | PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED, match_data, mctx);
|
||||
|
||||
piece = subject + start_offset;
|
||||
piece = ZSTR_VAL(subject_str) + start_offset;
|
||||
if (count >= 0 && limit) {
|
||||
goto matched;
|
||||
} else if (count == PCRE2_ERROR_NOMATCH || limit == 0) {
|
||||
@@ -1996,7 +1988,7 @@ matched:
|
||||
this is not necessarily the end. We need to advance
|
||||
the start offset, and continue. Fudge the offset values
|
||||
to achieve this, unless we're already at the end of the string. */
|
||||
if (start_offset < subject_len) {
|
||||
if (start_offset < ZSTR_LEN(subject_str)) {
|
||||
size_t unit_len = calculate_unit_length(pce, piece);
|
||||
start_offset += unit_len;
|
||||
} else {
|
||||
@@ -2009,20 +2001,17 @@ matched:
|
||||
|
||||
} else if (count == PCRE2_ERROR_NOMATCH || limit == 0) {
|
||||
not_matched:
|
||||
if (!result && subject_str) {
|
||||
if (result == NULL) {
|
||||
result = zend_string_copy(subject_str);
|
||||
break;
|
||||
}
|
||||
/* now we know exactly how long it is */
|
||||
alloc_len = result_len + subject_len - last_end_offset;
|
||||
if (NULL != result) {
|
||||
result = zend_string_realloc(result, alloc_len, 0);
|
||||
} else {
|
||||
result = zend_string_alloc(alloc_len, 0);
|
||||
}
|
||||
size_t segment_len = ZSTR_LEN(subject_str) - last_end_offset;
|
||||
alloc_len = result_len + segment_len;
|
||||
result = zend_string_realloc(result, alloc_len, 0);
|
||||
/* stick that last bit of string on our output */
|
||||
memcpy(ZSTR_VAL(result) + result_len, piece, subject_len - last_end_offset);
|
||||
result_len += subject_len - last_end_offset;
|
||||
memcpy(ZSTR_VAL(result) + result_len, piece, segment_len);
|
||||
result_len += segment_len;
|
||||
ZSTR_VAL(result)[result_len] = '\0';
|
||||
ZSTR_LEN(result) = result_len;
|
||||
break;
|
||||
@@ -2037,11 +2026,11 @@ error:
|
||||
}
|
||||
#ifdef HAVE_PCRE_JIT_SUPPORT
|
||||
if ((pce->preg_options & PREG_JIT)) {
|
||||
count = pcre2_jit_match(pce->re, (PCRE2_SPTR)subject, subject_len, start_offset,
|
||||
count = pcre2_jit_match(pce->re, (PCRE2_SPTR)ZSTR_VAL(subject_str), ZSTR_LEN(subject_str), start_offset,
|
||||
PCRE2_NO_UTF_CHECK, match_data, mctx);
|
||||
} else
|
||||
#endif
|
||||
count = pcre2_match(pce->re, (PCRE2_SPTR)subject, subject_len, start_offset,
|
||||
count = pcre2_match(pce->re, (PCRE2_SPTR)ZSTR_VAL(subject_str), ZSTR_LEN(subject_str), start_offset,
|
||||
PCRE2_NO_UTF_CHECK, match_data, mctx);
|
||||
}
|
||||
if (match_data != mdata) {
|
||||
@@ -2051,9 +2040,7 @@ error:
|
||||
|
||||
return result;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_pcre_replace_func */
|
||||
static zend_always_inline zend_string *php_pcre_replace_func(zend_string *regex,
|
||||
zend_string *subject_str,
|
||||
zend_fcall_info *fci, zend_fcall_info_cache *fcc,
|
||||
@@ -2067,14 +2054,11 @@ static zend_always_inline zend_string *php_pcre_replace_func(zend_string *regex,
|
||||
return NULL;
|
||||
}
|
||||
pce->refcount++;
|
||||
result = php_pcre_replace_func_impl(
|
||||
pce, subject_str, ZSTR_VAL(subject_str), ZSTR_LEN(subject_str), fci, fcc,
|
||||
limit, replace_count, flags);
|
||||
result = php_pcre_replace_func_impl(pce, subject_str, fci, fcc, limit, replace_count, flags);
|
||||
pce->refcount--;
|
||||
|
||||
return result;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_pcre_replace_array */
|
||||
static zend_string *php_pcre_replace_array(HashTable *regex,
|
||||
@@ -2173,16 +2157,14 @@ static zend_always_inline zend_string *php_replace_in_subject(
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_replace_in_subject_func */
|
||||
static zend_string *php_replace_in_subject_func(zend_string *regex_str, HashTable *regex_ht,
|
||||
static zend_string *php_replace_in_subject_func(zend_string *regex_str, const HashTable *regex_ht,
|
||||
zend_fcall_info *fci, zend_fcall_info_cache *fcc,
|
||||
zend_string *subject, size_t limit, size_t *replace_count, zend_long flags)
|
||||
{
|
||||
zend_string *result;
|
||||
|
||||
if (regex_str) {
|
||||
result = php_pcre_replace_func(
|
||||
regex_str, subject, fci, fcc, limit, replace_count, flags);
|
||||
result = php_pcre_replace_func(regex_str, subject, fci, fcc, limit, replace_count, flags);
|
||||
return result;
|
||||
} else {
|
||||
/* If regex is an array */
|
||||
@@ -2196,7 +2178,10 @@ static zend_string *php_replace_in_subject_func(zend_string *regex_str, HashTabl
|
||||
ZEND_HASH_FOREACH_VAL(regex_ht, regex_entry) {
|
||||
/* Make sure we're dealing with strings. */
|
||||
zend_string *tmp_regex_entry_str;
|
||||
zend_string *regex_entry_str = zval_get_tmp_string(regex_entry, &tmp_regex_entry_str);
|
||||
zend_string *regex_entry_str = zval_try_get_tmp_string(regex_entry, &tmp_regex_entry_str);
|
||||
if (UNEXPECTED(regex_entry_str == NULL)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Do the actual replacement and put the result back into subject
|
||||
for further replacements. */
|
||||
@@ -2213,13 +2198,11 @@ static zend_string *php_replace_in_subject_func(zend_string *regex_str, HashTabl
|
||||
return subject;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ preg_replace_func_impl */
|
||||
static size_t preg_replace_func_impl(zval *return_value,
|
||||
zend_string *regex_str, HashTable *regex_ht,
|
||||
static size_t php_preg_replace_func_impl(zval *return_value,
|
||||
zend_string *regex_str, const HashTable *regex_ht,
|
||||
zend_fcall_info *fci, zend_fcall_info_cache *fcc,
|
||||
zend_string *subject_str, HashTable *subject_ht, zend_long limit_val, zend_long flags)
|
||||
zend_string *subject_str, const HashTable *subject_ht, zend_long limit_val, zend_long flags)
|
||||
{
|
||||
zend_string *result;
|
||||
size_t replace_count = 0;
|
||||
@@ -2247,7 +2230,10 @@ static size_t preg_replace_func_impl(zval *return_value,
|
||||
and add the result to the return_value array. */
|
||||
ZEND_HASH_FOREACH_KEY_VAL(subject_ht, num_key, string_key, subject_entry) {
|
||||
zend_string *tmp_subject_entry_str;
|
||||
zend_string *subject_entry_str = zval_get_tmp_string(subject_entry, &tmp_subject_entry_str);
|
||||
zend_string *subject_entry_str = zval_try_get_tmp_string(subject_entry, &tmp_subject_entry_str);
|
||||
if (UNEXPECTED(subject_entry_str == NULL)) {
|
||||
break;
|
||||
}
|
||||
|
||||
result = php_replace_in_subject_func(
|
||||
regex_str, regex_ht, fci, fcc, subject_entry_str, limit_val, &replace_count, flags);
|
||||
@@ -2266,7 +2252,6 @@ static size_t preg_replace_func_impl(zval *return_value,
|
||||
|
||||
return replace_count;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void _preg_replace_common(
|
||||
zval *return_value,
|
||||
@@ -2410,8 +2395,8 @@ PHP_FUNCTION(preg_replace_callback)
|
||||
HashTable *subject_ht;
|
||||
zend_long limit = -1, flags = 0;
|
||||
size_t replace_count;
|
||||
zend_fcall_info fci;
|
||||
zend_fcall_info_cache fcc;
|
||||
zend_fcall_info fci = empty_fcall_info;
|
||||
zend_fcall_info_cache fcc = empty_fcall_info_cache;
|
||||
|
||||
/* Get function parameters and do error-checking. */
|
||||
ZEND_PARSE_PARAMETERS_START(3, 6)
|
||||
@@ -2424,7 +2409,7 @@ PHP_FUNCTION(preg_replace_callback)
|
||||
Z_PARAM_LONG(flags)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
replace_count = preg_replace_func_impl(return_value, regex_str, regex_ht,
|
||||
replace_count = php_preg_replace_func_impl(return_value, regex_str, regex_ht,
|
||||
&fci, &fcc,
|
||||
subject_str, subject_ht, limit, flags);
|
||||
if (zcount) {
|
||||
@@ -2436,13 +2421,11 @@ PHP_FUNCTION(preg_replace_callback)
|
||||
/* {{{ Perform Perl-style regular expression replacement using replacement callback. */
|
||||
PHP_FUNCTION(preg_replace_callback_array)
|
||||
{
|
||||
zval zv, *replace, *zcount = NULL;
|
||||
zval *replace, *zcount = NULL;
|
||||
HashTable *pattern, *subject_ht;
|
||||
zend_string *subject_str, *str_idx_regex;
|
||||
zend_long limit = -1, flags = 0;
|
||||
size_t replace_count = 0;
|
||||
zend_fcall_info fci;
|
||||
zend_fcall_info_cache fcc;
|
||||
|
||||
/* Get function parameters and do error-checking. */
|
||||
ZEND_PARSE_PARAMETERS_START(2, 5)
|
||||
@@ -2454,10 +2437,6 @@ PHP_FUNCTION(preg_replace_callback_array)
|
||||
Z_PARAM_LONG(flags)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
fci.size = sizeof(fci);
|
||||
fci.object = NULL;
|
||||
fci.named_params = NULL;
|
||||
|
||||
if (subject_ht) {
|
||||
GC_TRY_ADDREF(subject_ht);
|
||||
} else {
|
||||
@@ -2465,29 +2444,37 @@ PHP_FUNCTION(preg_replace_callback_array)
|
||||
}
|
||||
|
||||
ZEND_HASH_FOREACH_STR_KEY_VAL(pattern, str_idx_regex, replace) {
|
||||
if (!zend_is_callable_ex(replace, NULL, 0, NULL, &fcc, NULL)) {
|
||||
zend_argument_type_error(1, "must contain only valid callbacks");
|
||||
goto error;
|
||||
}
|
||||
if (!str_idx_regex) {
|
||||
zend_argument_type_error(1, "must contain only string patterns as keys");
|
||||
goto error;
|
||||
}
|
||||
|
||||
zend_fcall_info_cache fcc = empty_fcall_info_cache;
|
||||
zend_fcall_info fci = empty_fcall_info;
|
||||
fci.size = sizeof(zend_fcall_info);
|
||||
/* Copy potential trampoline */
|
||||
ZVAL_COPY_VALUE(&fci.function_name, replace);
|
||||
|
||||
replace_count += preg_replace_func_impl(&zv, str_idx_regex, /* regex_ht */ NULL, &fci, &fcc,
|
||||
if (!zend_is_callable_ex(replace, NULL, 0, NULL, &fcc, NULL)) {
|
||||
zend_argument_type_error(1, "must contain only valid callbacks");
|
||||
goto error;
|
||||
}
|
||||
|
||||
zval retval;
|
||||
replace_count += php_preg_replace_func_impl(&retval, str_idx_regex, /* regex_ht */ NULL, &fci, &fcc,
|
||||
subject_str, subject_ht, limit, flags);
|
||||
switch (Z_TYPE(zv)) {
|
||||
zend_release_fcall_info_cache(&fcc);
|
||||
|
||||
switch (Z_TYPE(retval)) {
|
||||
case IS_ARRAY:
|
||||
ZEND_ASSERT(subject_ht);
|
||||
zend_array_release(subject_ht);
|
||||
subject_ht = Z_ARR(zv);
|
||||
subject_ht = Z_ARR(retval);
|
||||
break;
|
||||
case IS_STRING:
|
||||
ZEND_ASSERT(subject_str);
|
||||
zend_string_release(subject_str);
|
||||
subject_str = Z_STR(zv);
|
||||
subject_str = Z_STR(retval);
|
||||
break;
|
||||
case IS_NULL:
|
||||
RETVAL_NULL();
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
--TEST--
|
||||
preg_replace_callback() 3
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
try {
|
||||
var_dump(preg_replace_callback(1,2,3));
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
try {
|
||||
var_dump(preg_replace_callback(1,2,3,4));
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
|
||||
$a = 5;
|
||||
try {
|
||||
var_dump(preg_replace_callback(1,2,3,4,$a));
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
preg_replace_callback(): Argument #2 ($callback) must be a valid callback, no array or string given
|
||||
preg_replace_callback(): Argument #2 ($callback) must be a valid callback, no array or string given
|
||||
preg_replace_callback(): Argument #2 ($callback) must be a valid callback, no array or string given
|
||||
112
ext/pcre/tests/preg_replace_callback_array_trampoline.phpt
Normal file
112
ext/pcre/tests/preg_replace_callback_array_trampoline.phpt
Normal file
@@ -0,0 +1,112 @@
|
||||
--TEST--
|
||||
preg_replace_callback_array() with a trampoline
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class TrampolineTest {
|
||||
public function __call(string $name, array $arguments): string {
|
||||
echo 'Trampoline for ', $name, PHP_EOL;
|
||||
if ($name === 'trampolineThrow') {
|
||||
throw new Exception('boo');
|
||||
}
|
||||
return "'" . $arguments[0][0] . "'";
|
||||
}
|
||||
}
|
||||
$o = new TrampolineTest();
|
||||
$callback = [$o, 'trampoline'];
|
||||
$callbackThrow = [$o, 'trampolineThrow'];
|
||||
|
||||
$regexesToTest = [
|
||||
[
|
||||
'@\b\w{1,2}\b@' => $callback,
|
||||
'~\A.~' => $callback,
|
||||
],
|
||||
[
|
||||
'@\b\w{1,2}\b@' => $callback,
|
||||
'~\A.~' => $callbackThrow,
|
||||
],
|
||||
[
|
||||
'@\b\w{1,2}\b@' => $callback,
|
||||
'~\A.~' => new stdClass(),
|
||||
],
|
||||
];
|
||||
|
||||
$subjectsToTest = [
|
||||
[
|
||||
'a b3 bcd',
|
||||
'v' => 'aksfjk',
|
||||
12 => 'aa bb',
|
||||
['xyz'],
|
||||
],
|
||||
'a b3 bcd',
|
||||
[
|
||||
new stdClass(),
|
||||
],
|
||||
new stdClass(),
|
||||
];
|
||||
|
||||
foreach ($regexesToTest as $regex) {
|
||||
foreach ($subjectsToTest as $subject) {
|
||||
try {
|
||||
$matches = preg_replace_callback_array($regex, $subject);
|
||||
var_dump($matches);
|
||||
} catch (Throwable $e) {
|
||||
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
|
||||
Warning: Array to string conversion in %s on line %d
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
array(4) {
|
||||
[0]=>
|
||||
string(14) "'''a' 'b3' bcd"
|
||||
["v"]=>
|
||||
string(8) "'a'ksfjk"
|
||||
[12]=>
|
||||
string(11) "'''aa' 'bb'"
|
||||
[13]=>
|
||||
string(7) "'A'rray"
|
||||
}
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
string(14) "'''a' 'b3' bcd"
|
||||
Error: Object of class stdClass could not be converted to string
|
||||
TypeError: preg_replace_callback_array(): Argument #2 ($subject) must be of type array|string, stdClass given
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
|
||||
Warning: Array to string conversion in %s on line %d
|
||||
Trampoline for trampolineThrow
|
||||
Exception: boo
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampolineThrow
|
||||
Exception: boo
|
||||
Error: Object of class stdClass could not be converted to string
|
||||
TypeError: preg_replace_callback_array(): Argument #2 ($subject) must be of type array|string, stdClass given
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
|
||||
Warning: Array to string conversion in %s on line %d
|
||||
TypeError: preg_replace_callback_array(): Argument #1 ($pattern) must contain only valid callbacks
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
TypeError: preg_replace_callback_array(): Argument #1 ($pattern) must contain only valid callbacks
|
||||
Error: Object of class stdClass could not be converted to string
|
||||
TypeError: preg_replace_callback_array(): Argument #2 ($subject) must be of type array|string, stdClass given
|
||||
133
ext/pcre/tests/preg_replace_callback_trampoline.phpt
Normal file
133
ext/pcre/tests/preg_replace_callback_trampoline.phpt
Normal file
@@ -0,0 +1,133 @@
|
||||
--TEST--
|
||||
preg_replace_callback() with a trampoline
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class TrampolineTest {
|
||||
public function __call(string $name, array $arguments): string {
|
||||
echo 'Trampoline for ', $name, PHP_EOL;
|
||||
if ($name === 'trampolineThrow') {
|
||||
throw new Exception('boo');
|
||||
}
|
||||
return "'" . $arguments[0][0] . "'";
|
||||
}
|
||||
}
|
||||
$o = new TrampolineTest();
|
||||
$callback = [$o, 'trampoline'];
|
||||
$callbackThrow = [$o, 'trampolineThrow'];
|
||||
|
||||
$regexesToTest = [
|
||||
[
|
||||
'@\b\w{1,2}\b@',
|
||||
'~\A.~',
|
||||
],
|
||||
'@\b\w{1,2}\b@',
|
||||
[
|
||||
new stdClass(),
|
||||
],
|
||||
];
|
||||
|
||||
$subjectsToTest = [
|
||||
[
|
||||
'a b3 bcd',
|
||||
'v' => 'aksfjk',
|
||||
12 => 'aa bb',
|
||||
['xyz'],
|
||||
],
|
||||
'a b3 bcd',
|
||||
[
|
||||
new stdClass(),
|
||||
],
|
||||
new stdClass(),
|
||||
];
|
||||
|
||||
foreach ([$callback, $callbackThrow] as $fn) {
|
||||
foreach ($regexesToTest as $regex) {
|
||||
foreach ($subjectsToTest as $subject) {
|
||||
try {
|
||||
$matches = preg_replace_callback($regex, $fn, $subject);
|
||||
var_dump($matches);
|
||||
} catch (Throwable $e) {
|
||||
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
|
||||
Warning: Array to string conversion in %s on line %d
|
||||
Trampoline for trampoline
|
||||
array(4) {
|
||||
[0]=>
|
||||
string(14) "'''a' 'b3' bcd"
|
||||
["v"]=>
|
||||
string(8) "'a'ksfjk"
|
||||
[12]=>
|
||||
string(11) "'''aa' 'bb'"
|
||||
[13]=>
|
||||
string(7) "'A'rray"
|
||||
}
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
string(14) "'''a' 'b3' bcd"
|
||||
Error: Object of class stdClass could not be converted to string
|
||||
TypeError: preg_replace_callback(): Argument #3 ($subject) must be of type array|string, stdClass given
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
|
||||
Warning: Array to string conversion in %s on line %d
|
||||
array(4) {
|
||||
[0]=>
|
||||
string(12) "'a' 'b3' bcd"
|
||||
["v"]=>
|
||||
string(6) "aksfjk"
|
||||
[12]=>
|
||||
string(9) "'aa' 'bb'"
|
||||
[13]=>
|
||||
string(5) "Array"
|
||||
}
|
||||
Trampoline for trampoline
|
||||
Trampoline for trampoline
|
||||
string(12) "'a' 'b3' bcd"
|
||||
Error: Object of class stdClass could not be converted to string
|
||||
TypeError: preg_replace_callback(): Argument #3 ($subject) must be of type array|string, stdClass given
|
||||
|
||||
Warning: Array to string conversion in %s on line %d
|
||||
Error: Object of class stdClass could not be converted to string
|
||||
Error: Object of class stdClass could not be converted to string
|
||||
Error: Object of class stdClass could not be converted to string
|
||||
TypeError: preg_replace_callback(): Argument #3 ($subject) must be of type array|string, stdClass given
|
||||
Trampoline for trampolineThrow
|
||||
|
||||
Warning: Array to string conversion in %s on line %d
|
||||
Exception: boo
|
||||
Trampoline for trampolineThrow
|
||||
Exception: boo
|
||||
Error: Object of class stdClass could not be converted to string
|
||||
TypeError: preg_replace_callback(): Argument #3 ($subject) must be of type array|string, stdClass given
|
||||
Trampoline for trampolineThrow
|
||||
|
||||
Warning: Array to string conversion in %s on line %d
|
||||
Exception: boo
|
||||
Trampoline for trampolineThrow
|
||||
Exception: boo
|
||||
Error: Object of class stdClass could not be converted to string
|
||||
TypeError: preg_replace_callback(): Argument #3 ($subject) must be of type array|string, stdClass given
|
||||
|
||||
Warning: Array to string conversion in %s on line %d
|
||||
Error: Object of class stdClass could not be converted to string
|
||||
Error: Object of class stdClass could not be converted to string
|
||||
Error: Object of class stdClass could not be converted to string
|
||||
TypeError: preg_replace_callback(): Argument #3 ($subject) must be of type array|string, stdClass given
|
||||
Reference in New Issue
Block a user