Req #67817 [Com]: RFE: permit repeat declaration of the same function to skip rather than fail
| From: | php at richardneill dot org | Date: | Sun, 10 Aug 2014 01:01:43 +0000 |
| Subject: | Req #67817 [Com]: RFE: permit repeat declaration of the same function to skip rather than fail | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-187059@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=67817&edit=1
ID: 67817
Comment by: php at richardneill dot org
Reported by: php at richardneill dot org
Summary: RFE: permit repeat declaration of the same function
to skip rather than fail
Status: Not a bug
Type: Feature/Change Request
Package: Scripting Engine problem
PHP Version: 5.5.15
Block user comment: N
Private report: N
New Comment:
I do see your point about the architecture, although even if I had put all the functions in separate
pages, so that, (in my example),
details.php (the presentation layer) contains no functions, but itself
requires header.php and functions.php (which contain only functions).
this still wouldn't help, unless every single function within the other files is also wrapped
in function_exists().
I admit my example is a quick and dirty hack, trying to write a 1 hour wrapper around a 3-man-year
website, which is reasonably well architected and factored, but by no means perfect, and without the
time for a major job of refactoring.
Also, while important functions and classes do go into separate files, I can't believe most
programmers are immune from having the occasional specific 3-line function within their presentation
layer.
Furthermore, this is an interesting way to attract bugs: it is relatively rare to test the
convoluted code-path, whereas the normal "straight through" path is common. Adding a new
function would work perfectly well in the common case, but would break the rare case (and most of us
are good, but not 100% perfect at testing every last permutation).
Anyway, it seems to me that my proposal would be simple to implement, have no negative side effects,
and eliminate a common frustration of wasted time, and sometimes corner-case crashes. Since the
intent of the programmer is unambiguous, why not do it? It would also be compatible with bash,
perl,and python, all of which permit this.
I'm sorry that I don't know the PHP internals well enough to offer a patch - but I'd
have thought it's quite straightforward, changing the parser's logic on encountering a
function from:
if (function F is already defined){
print error message (earlier_file_linenum, this_file_linenum)
die()
}else{
parse function F
}
to:
if (function F is already defined){
if (this_file_linenum == earlier_file_linenum
skip_to_end_of F
raise E_NOTICE
}else{
print error message (earlier_file_linenum, this_file_linenum)
die()
}
}else{
parse function F
}
Previous Comments:
------------------------------------------------------------------------
[2014-08-09 23:59:42] requinix@php.net
That's a problem of architecture: you've clearly written your pages so that they cannot
all be executed at once, but that's exactly what you're trying to do with them.
The standard practice of putting classes and functions in separate files, away from the
"presentation" files, would save you from this problem.
------------------------------------------------------------------------
[2014-08-09 23:17:28] php at richardneill dot org
Thanks for your comment; I did already know about require_once(). Sorry if my test case was too
simple; there are many better reasons for doing this, notably if the files to be included (or their
children) contain a mix of functions and other code, in which case we only want to define the
functions once, but we need to invoke the rest of the code every time.
Here is a real example. I have a (complicated) website written in PHP, with multiple users. Each
page is dynamically generated, according to both the query-string and the credentials saved in
$_SESSION.
A user wants to export his data, essentially crawling part of the site, while logged in. Thus, we
have something like the following (simplified) in export.php:
function capture_html ($page, $get){
$_GET = $get; $_POST=array();
//but, we explicitly want to keep $_SESSION
ob_start();
include ($page);
$html = ob_get_contents();
ob_end_clean;
return ($html);
}
//iterate over multiple sets of pages and files:
file_put_contents("1.html",capture_html("details.php", array("id"
=> "5") ));
file_put_contents("2.html",capture_html("details.php", array("id"
=> "6") ));
file_put_contents("3.html",capture_html("messages.php",array("id"
=> "532")));
...
//and now zip the archive and offer the .zip to the user.
This is admittedly ugly in terms of recursion. The problem arises when the same $page is captured
twice with different parameters: all the functions which normally don't clash then conflict
with themselves. In this example, repeated use of file_get_contents($url) would be no good, because
the view of ($url) would be for a non-loggedin user.
I hope that makes sense.
------------------------------------------------------------------------
[2014-08-09 22:00:48] pajoye@php.net
That's why include/require_once exists.
------------------------------------------------------------------------
[2014-08-09 21:07:27] php at richardneill dot org
Description:
------------
At the moment, PHP will not let us re-declare an existing function, but instead has the error:
"Cannot redeclare FUNCNAME() (previously declared in FILE:LINE)"
That's fine, and I understand why, unlike, say bash, we can't/shouldn't be able to
change a function definition.
However, it's rather a pain if you end up with multiple indirectly include()d files some of
which get included more than once, and you forgot to wrap every single function definition with:
if (!function_exists("FUNCNAME")){
function FUNCNAME(...){
...
}}
My request is that, rather than throwing an error the second time, if PHP is encountering the *same*
function in the *same* file, it should simply ignore the duplicate definition (and throw an
E_NOTICE).
This ought to be easy to implement (since PHP already knows the filename/line-num of the original
definition at the time it reaches the duplicate), and the parser need merely ignore the duplicate.
It should also not violate the principle of least-surprise, because if the function is identical,
then even if it were re-defined, the programmer would expect it to do the same thing. So I believe
this is an easy and uncontroversial win for the common case.
Thank you for your consideration.
Test script:
---------------
----- begin file inner.php ---
<?php
function a(){
echo "A\n";
}
a();
?>
------ end file --------------
----- begin file main.php ---
<?php
include ("inner.php");
include ("inner.php");
?>
------ end file --------------
Expected result:
----------------
This should print:
A
A
Actual result:
--------------
A
PHP Fatal error: Cannot redeclare a() (previously declared in inner.php.3) in inner.php on line 4
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=67817&edit=1