rfc:skipparams

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
rfc:skipparams [2013/09/02 07:15] – [Implementation] stasrfc:skipparams [2017/09/22 13:28] (current) – external edit 127.0.0.1
Line 1: Line 1:
 ====== Skipping optional parameters for functions ====== ====== Skipping optional parameters for functions ======
-  * Version: 2.0 +  * Version: 3.0 
-  * Date: 2013-09-01+  * Date: 2015-01-01
   * Author: Stas Malyshev <stas@php.net>   * Author: Stas Malyshev <stas@php.net>
-  * Status: Under Discussion +  * Status: Declined 
-  * Implementation: https://github.com/php/php-src/pull/426, https://github.com/smalyshev/php-src/tree/skip_params+  * Implementation: https://github.com/smalyshev/php-src/tree/skip_params7
 ===== Introduction ===== ===== Introduction =====
  
-As PHP does not have named parameter supportvery common for function is to have many optional arguments, like this:+In PHP, it is very common for function is to have many optional arguments, like this:
  
      function create_query($where, $order_by, $join_type='', $execute = false, $report_errors = true)      function create_query($where, $order_by, $join_type='', $execute = false, $report_errors = true)
Line 23: Line 23:
 Of course, if we ever get implementation of named parameters, it may also solve this problem, but until we do, this can be a partial solution.  Of course, if we ever get implementation of named parameters, it may also solve this problem, but until we do, this can be a partial solution. 
  
-Only optional parameters can be skipped this way, skipping non-optional one will produce the same error it does now when function is not given enough parameters.+Only declared optional parameters can be skipped this way, skipping non-optional one will produce the same error it does now when function is not given enough parameters. Also, for variadic functions, variadic parameters can not be skipped - only parameters that are explicitly declared and marked optional can be skipped
  
 ===== Implementation ===== ===== Implementation =====
  
-On the engine level, it will be implemented by putting NULL in the place where the parameter is passed. Functions dealing with argument handling will be updated.+On the engine level, it will be implemented by putting IS_UNDEF value in the place where the parameter is passed. Functions dealing with argument handling will be updated.
  
-See example implementation above. See tests for examples of most common uses cases. +See example implementation at: https://github.com/php/php-src/pull/981 
 + 
 +See tests there for examples of most common uses cases. 
  
 ===== User functions ===== ===== User functions =====
Line 37: Line 39:
 ===== Internal functions ===== ===== Internal functions =====
  
-For internal functions, parameter parser will ignore the NULLs, thus leaving the defaults supplied by the caller intact. Again, skipping non-optional parameter is an error. +For internal functions, parameter parser will ignore the skipped parameters, thus leaving the defaults supplied by the caller intact. Again, skipping non-optional parameter is an error. For variadic parameters, as per above, skipping is not allowed, unless specifically requested by  function declaration
  
-Variadic functions will not return skipped parameters in argc and argveffectively ignoring them, so:+Thusthis code is an error:
  
        var_dump(2,default,1);        var_dump(2,default,1);
  
-is the same as:+but this is not:
  
-       var_dump(2,1);+       call_user_func('foo', 2, default, 1); 
 + 
 +since call_user_func is specifically described as accepting defaults. 
  
 ===== func_get_args() ===== ===== func_get_args() =====
  
-func_get_args() will skip parameters that are not supplied, so it would provide just the parameters that are actually supplied to the function. Thus, this code: +func_get_args() will use default values for parameters that are not supplied. Because of how PHP 7 engine works, it is not possible to distinguish skipped parameter from parameter where default value is actually passed. 
- +
-     function test($a=1, $b=2, $c=3) { +
-        var_dump(func_get_args()); +
-     } +
- +
-     test(1,default,4); +
- +
-will produce: +
- +
-      array(2) { +
-        [0]=> +
-        int(1) +
-        [2]=> +
-        int(4) +
-      } +
- +
-This means that if you are looping over func_get_args() result, you should use foreach() and not counter-based for(). +
-func_num_args() will also ignore skipped parameters and give only the number of parameters actually passed.  +
-func_get_arg() will return false for parameter that was not passed. +
  
 ===== call_user_func_array() ===== ===== call_user_func_array() =====
  
-call_user_func_array() will allow skipping arguments too by skipping them in supplied arguments array, like this: +Currently, call_user_func_array does not support skipping parameters due to the fact that previously it accepted any array as parameters listbut supporting skipping parameters would mean only sequential indexed numeric array will be accepted
- +
-      call_user_func_array('test', array(42, 2=>43, 4=>44)); +
- +
-call_user_func will allow argument skipping directly: +
- +
-      call_user_func('test', 42, default, 44); +
- +
-with the same result.+
  
 ===== Internal API changes ===== ===== Internal API changes =====
-Parameters stored as zval** in the engine. For skipped parameter, the value stored is NULL instead of zval* to specific argument+Parameters stored as array of zvals n the engine. For skipped parameter, the zval type is stored as IS_UNDEF
  
-zend_parse_parameter() would ignore parameters marked as default - meaning, it will not assign any value to the underlying variable. This is unless the parameter is marked as !, in which case the parameter would be nullified just as if null were passed. This means you can not have variables marked as ! with different behavior between null and 'default', but I did not find any such cases to be required. +zend_parse_parameter() would ignore parameters marked as skipped/default - meaning, it will not assign any value to the underlying variable. This is unless the parameter is marked as !, in which case the parameter would be nullified just as if null were passed. This means you can not have variables marked as ! with different behavior between null and 'default', but I did not find any such cases to be required. 
  
-For variadic parameters like + and *skipped parameters will be ignored and not included in the list as if they were not passed. In other words+ and * will never return NULLs among parameters+If certain function wants to disallow skipping parameters, it should use option ZEND_PARSE_PARAMS_NODEFAULT with zend_parse_parameters_ex(). This may be when internal function has optional arguments but does not have any defaults for them. In this caseskipped parameters will cause a catchable fatal error
  
-If certain function wants to disallow skipping parameters, it should use option ZEND_PARSE_PARAMS_NODEFAULT with zend_parse_parameters_ex(). In this case, skipped parameters will cause . For older APIs, zend_get_parameters_array_nodefault() is available which will fail with E_WARNING "Parameter %d missing" if any skipped parameters are passed (i.e. would never return NULLs as parameters). +ZEND_NUM_ARGS() is always the number of parameters in function call, so skipped parameters are counted there. 
- +
-ZEND_NUM_ARGS() is always the number of parameters in function call, so skipped parameters are counted there. But trying to get a skipped parameter with API functions will produce NULL+
  
 ===== User request examples ===== ===== User request examples =====
Line 103: Line 78:
   * http://stackoverflow.com/q/4681987/214196 (for Delphi)   * http://stackoverflow.com/q/4681987/214196 (for Delphi)
   * http://stackoverflow.com/q/4435918/214196 (for AS)   * http://stackoverflow.com/q/4435918/214196 (for AS)
 +  * http://stackoverflow.com/q/812058/214196 (for Ruby)
 +===== Issues raised =====
 +   
 +* Internal functions that declare parameters as optional but fail to provide proper defaults and rely on ZEND_NUM_ARGS to figure out if to use default or not may be broken. The patch fixes all instances of this in the core extensions, but third-party extensions may need to be fixed too. This applies only to ones that check ZEND_NUM_ARGS() manually in the code instead of using zend_parse_parameters().
  
-===== Issues raised ===== +* This RFC does not prevent named parameters implementation - in fact, a lot of cleanup to the code mentioned above is also necessary for named parameters implementation, since it would require the same level of care with providing the defaults. Both features can be used in parallel, and thus this RFC is a complimentary functionality for potential named parameters implementation. 
-    * Support for internal functions doing manual ZEND_NUM_ARGS(). I've looked into all functions in the standard distributionbut PECL extensions that are not using zend_parse_parameters or do weird things with zval-type ones without properly initializing them or checking the output results, may require fixing, otherwise they may crash if "default" is passed to them due to null pointer referenceThis crash doesn't seem to be dangerous security-wise, but would of course be unpleasant+ 
 +===== Vote ===== 
 + 
 +Since this RFC changes the language semantics, the 2/3+1 vote majority is required for it to passThe vote is a straight Yes/No vote.  
 + 
 +<doodle title="Should PHP 7 support parameter skipping as described in this RFC?" auth="stas" voteType="single" closed="true"> 
 +   * Yes 
 +   * No 
 +</doodle> 
 + 
 +The vote concludes on the end of the day, PST, February 21th.
  
 ===== Changelog ===== ===== Changelog =====
Line 111: Line 100:
   * 2012-04-13 First draft.   * 2012-04-13 First draft.
   * 2012-07-07 Changed empty parameter to use 'default'   * 2012-07-07 Changed empty parameter to use 'default'
-  * Added Zend API description+  * 2013-09-01 Added Zend API description 
 +  * 2015-01-01 Updated for PHPNG
rfc/skipparams.1378106154.txt.gz · Last modified: 2017/09/22 13:28 (external edit)