Edit report at https://bugs.php.net/bug.php?id=65181&edit=1
ID: 65181
Comment by: area at areasas dot net
Reported by: ducciogrun at gmail dot com
Summary: Merging the "do {} while(cond)" and "while(cond){}"
structures
Status: Wont fix
Type: Feature/Change Request
Package: *General Issues
Operating System: Any
PHP Version: Irrelevant
Block user comment: N
Private report: N
New Comment:
.. I also had the same problem following the most common indication about the
SQLite3 connection through PHP so that I propose two alternatives:
basic code:
===================================
$wp_sqlite = new SQLite3('../<dir>/<filename>');
$results = $wp_sqlite->query('SELECT * FROM test;');
===================================
alternative 1 (using "if(!empty..." to check if the $row has got a record):
===================================
$rows = array();
do {
$row = $results->fetchArray(SQLITE3_ASSOC);
if (!empty($row)) $rows[] = $row;
}
while ($row);
===================================
alternative 2 (using "array_pop" to just "pop" the last item of the array which
is empty, due to the "do" construct):
===================================
$rows = array();
do {
$row = $results->fetchArray(SQLITE3_ASSOC);
$rows[] = $row;
}
while ($row);
array_pop($rows);
====================================
I had to do this way because the solution defined elegant (which really is
elegant) is not applicable where you need an assignment so to have variable to
be managed in the further code.
"alternative 2" is more efficient when tons of records has to be fetched.
I hope it helps.
Carmine Iaciofano
Previous Comments:
------------------------------------------------------------------------
[2013-07-04 21:35:07] ducciogrun at gmail dot com
Please note that this is not a bug report/complaint/help request, but rather a
new feature request. Though the assignment in condition is a common practice,
it
is prone to errors as it is easy to put too many or too few equal signs, $a =
$b
instead of $a == $b. There is a rationale behind signaling a warning for an
assignment in condition.
In my experience putting everything inside a function is not the best solution,
as it makes the code less understandable
(everything_that_must_be_done_before_the_condition_but_that_I_didnt_have_space_t
o_do_it_inline_in_the_condition() is not exactly a well defined function).
Maybe
closures would help in code readability, but what I always used was a "if(cond)
break;" inside of an infinite loop.
On a more abstract level, php forces you to make a choice, either the condition
is at the beginning, or it is at the end. Must it be like that?
The for loop already has a predefined place for code to be executed before the
condition check, and another place for code that goes after the condition
check.
But it's a quite specific loop, and the space for code before the condition is
rather small. The while could be more flexible. And as far as I know, you're
right, no other language has anything similar.
For sure there is a need for executing some code before and some code after the
condition. Can we live without a standardized structure that does it? Sure we
can. In the past we also lived without the while and for loop, as the goto or
even better the assembly JMP could handle each and every possible situation.
The need is there, what should be discussed if it is "better" to introduce a
new
structure or just live with one of the many "hacks" that php already offers
(functions, closures, breaks inside infinite loops, nesting of structures).
I don't really have a clue whether the do{}while{} is the best choice or not.
That was just my first idea.
------------------------------------------------------------------------
[2013-07-02 14:00:36] [email protected]
I'm sure that your IDE provides a way to disable this warning (though I do
wonder why they included it in the first place, as this is a pretty standard
idiom in PHP.)
If the expression grows too complicated, the most obvious solution is to just
put the code in a separate method / function.
This do { ... } while (...) { ... } structure is not present in any other
language that I'm aware of and is not particularly intelligible.
------------------------------------------------------------------------
[2013-07-02 12:36:24] ducciogrun at gmail dot com
@ab: Assignments in condition are not nice to read but one can live with them,
with or without the explicit true or false check.
But sometimes one has to do more complicated tasks (to name some dumb ones
related to that short piece of code, maybe check if the connection to the
database is still alive before fetching new data, check if there is enough
memory available, update the log to inform that the process is about to fetch
another row, or whatever).
Which one is more readable:
while (false !== ((memory_get_usage(true)<MYSCRIPT_MAX_MEMORY) && mysql_ping()
&& fwrite($log, "Start fetching a new row...") && $row = $result-
>fetch_assoc()));
or
do {
if(memory_get_usage(true)<MYSCRIPT_MAX_MEMORY) {
/* write to log the reaching of max memory usage */
break;
}
if(mysql_ping()) {
/* reestablish connection and send again the query */
}
fwrite($log, "Start fetching a new row...");
$row = $result->fetch_assoc();
} while ($row) {
/* do what you have to do with the row */
}
Now, let's be honest, there are several ways to do that, for example to create
a
specific do_prefetch_jobs_and_return_row() function, nesting "if" and other
structures, but IMHO they are all less elegant :-)
I opened this feature request to see if I'm the only one that would like to see
this construct implemented, before jumping directly on the Php source code
------------------------------------------------------------------------
[2013-07-02 08:45:05] [email protected]
What about while (false !== ($row = $result->fetch_assoc())); ?
------------------------------------------------------------------------
[2013-07-02 08:35:45] ducciogrun at gmail dot com
Description:
------------
An example directly from the Php documentation
(http://php.net/manual/en/function.mysql-fetch-assoc.php):
/* fetch associative array */
while ($row = $result->fetch_assoc()) {
printf ("%s (%s)\n", $row["Name"], $row["CountryCode"]);
}
It's old, it's prone to errors and my IDE (Zend Studio) always reports a
"assignment in condition" warning. And many times thw work to be done on the
first iteration is a lot more complicated than that.
One solution is to duplicate code:
/* fetch associative array */
$row = $result->fetch_assoc();
while ($row) {
printf ("%s (%s)\n", $row["Name"], $row["CountryCode"]);
$row = $result->fetch_assoc(); //Duplicate code
}
But it is not the best, both to read and to mantain.
An elegant solution could be the following structure:
/* fetch associative array */
do {
$row = $result->fetch_assoc();
} while ($row) {
printf ("%s (%s)\n", $row["Name"], $row["CountryCode"]);
}
Merging "do { } while(cond)" and "while(cond){}" would come handy anytime there
is code that should be run at the first iteration and at any subsequent
iteration, before the condition is checked.
The same purpose could be achieved by
/* fetch associative array */
do {
$row = $result->fetch_assoc();
if($row) {
printf ("%s (%s)\n", $row["Name"], $row["CountryCode"]);
}
} while ($row);
But it adds a level of nesting and it forces php to check twice the condition.
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=65181&edit=1