FAQ

[PHP-INTERNALS] zend_parse_parameters() improvements

Gustavo Lopes
Jul 19, 2012 at 11:50 pm

Em Fri, 20 Jul 2012 00:20:49 +0200, Sara Golemon <pol...@...net> escreveu:

Okay, well... the main pieces of feedback I'd give on it then is to not
change the behavior of the '!' modifier. That's bad BC. Rather,
introduce
a new modifier for checking if a parameter was passed. Secondly, make
these two separate patches as the new modifier is a separate feature from
the single-arg parameter parsing.

FWIW, there are a few examples of this being handled by defining the
default value of the parameter to something non-sensical (such as a
length
of -1), then doing zpp with "|l!" would leave the default -1 alone when
NULL is passed, and you can treat as "not passed". Granted this is a bit
of a hack and won't work for all situations. Your approach is more
comprehensive, just saying that for many cases it's not strictly needed.
Stas managed to confuse you :)

On an implementation level, this has nothing to do with default parameter
values and unpassed parameters. As always, if you don't pass an argument,
the pointers you give to zpp won't be touched. The behavior of ! is not
changed insofar as it was not possible to use it with l, d or b (well
actually it was ignored, so if anyone used l! their code will break as you
now have to pass an extra argument, but it was wrong in the first place).

Default parameters and unpassed parameters enter the scene because it's
idiomatic to pass NULL to have the same effect as not passing that
parameter.

Consider this hypothetical internal function with signature:

mb_substr(string $str, int $start [, int $length [, string $encoding ]])

Let's also imagine we want that the effect of not passing $length cannot
be triggered by a specific value of $length (like -1) because the whole
integer domain is used for something else. We have this check:

if (ZEND_NUM_ARGS() < 3) { /* do special stuff */ }

But now I cannot pass $encoding and not pass $length. I also can't wrap
the function and pass-through arguments in an easy fashion.

An idiomatic solution for this is to use NULL as a special value. In
userspace:

function mb_substr($str, $start, $length=NULL, $encoding=NULL) {
if ($length === null) { /* do special stuff */ }

However, the same is not possible with zpp because if we use 'l' and we
send NULL, we'll get 0, which we cannot distinguish from an actual 0 being
passed (or false, etc.).

The first commit in the branch solves this problem. We could write:

char *str, *encoding = NULL;
int str_len, encoding_len;
long start, length;
zend_bool length_is_null = 0;
zend_parse_parameters(..., "sl|l!s!, &str, &str_len, &start,
&length, &length_is_null, &encoding)

Then we have length_is_null == 0 <=> $length was not passed or NULL was
its value (just like the userland check above).

--
Gustavo Lopes
reply

Search Discussions

Discussion Posts

Previous

Follow ups

Related Discussions

Discussion Navigation
viewthread | post
posts ‹ prev | 12 of 22 | next ›