I have two "buttons" to move the array cursor to the next record or to the prior record. The function using "next" to move to the next (older) record works correctly.
However, the function to move to the prior ("prev") record (which is toward the top of the array) does not work correctly. I suspect that may be related to using "mysqli_data_seek". My belief was that it would set the cursor to the current location and then backtrack to the previous record. Instead the cursor continues to moves forward as if "next" was used instead of "prev". How can I backtrack to the prior record?
function return_next_issue()
{
// Newer Issue - Moves up towards the top of the array.
// mysqli_data_seek($_SESSION['result'], 0);
while($row=mysqli_fetch_array($_SESSION['result'], MYSQL_NUM))
{
if($_SESSION['issuenum'] == $row[0])
{
break;
}
}
prev($_SESSION['result']);
$row=mysqli_fetch_row($_SESSION['result']);
return $row[0];
}
since the mysqli_result object is in the session and shared, you might want to initialize the internal pointer to 0 to make sure you know you are going to seek from the start. You can also create a variable that increments over the iteration to identify the index you need and seek for the previous one.
function return_next_issue()
{
// Newer Issue - Moves up towards the top of the array.
$i = 0;
mysqli_data_seek($_SESSION['result'], 0);
while($row=mysqli_fetch_array($_SESSION['result'], MYSQL_NUM))
{
if($_SESSION['issuenum'] == $row[0])
{
break;
}
$i++;
}
mysqli_data_seek($_SESSION['result'], $i - 1);
$row=mysqli_fetch_row($_SESSION['result']);
return $row[0];
}
Please note that your code won't work if $_SESSION['issuenum'] is 0 or if is greater than the number of rows available, and therefore so do the code I am providing.
Related
So i'm having trouble getting a bit of code to work. Essentially what I want to do is:
in a foreach loop, if a given array value is set, compare that existing value to the current loop value, then set the existing value = current value (for the iteration) if the existing value is already greater than current val. Here is the code i'm working with:
if ($usedebayxml->ack == 'Success') {
foreach($usedebayxml->searchResult->item as $key => $value) {
if(isset($newarray[1]['TotalCost'])) {
if($newarray[1]['TotalCost'] > ((integer)$value->shippingInfo->shippingServiceCost + (integer)$value->sellingStatus->currentPrice)) {
$newarray[1]['Title'] = (string)$value->title ;
$newarray[1]['ShippingCost'] = (integer)$value->shippingInfo->shippingServiceCost;
$newarray[1]['Price'] = (integer)$value->sellingStatus->currentPrice;
$newarray[1]['Condition'] = 'New';
$newarray[1]['TotalCost'] = (integer)$value->shippingInfo->shippingServiceCost + (integer)$value->sellingStatus->currentPrice;
}
}
else
$newarray[1]['Title'] = (string)$value->title;
$newarray[1]['ShippingCost'] = (integer)$value->shippingInfo->shippingServiceCost;
$newarray[1]['Price'] = (integer)$value->sellingStatus->currentPrice;
$newarray[1]['Condition'] = 'Used';
$newarray[1]['TotalCost'] = (integer)$value->shippingInfo->shippingServiceCost + (integer)$value->sellingStatus->currentPrice;
}
}
With this code, what is returned is ultimately the values in the LAST key object in the xml file (im using simpleXML if that helps). In other words, i don't think the first if block (if isset) is being entered into, and the values are being set to whatever the values are for the current iteration. Can anyone see any flaw in my logic here? I've been stumped on this one for a while.
I am a supreme idiot. The logic here is fine, i was just missing a { for the opening else block. dur! After adding this, this bit of code works as intended :)
I'm surprised though that i wasn't throwing any errors without having this....I think that was probably throwing me off in determining why it wasn't working originally.
For ex. If I have a function rand(0,2). How do i build a function such that
resc(100,rand(0,2));
Prints the value of rand(0,2) 100 times? For that matter. Any function that is printable.
I tried this.But doesnt seem to work.
<?php
function resc($i, $f) {
if ($i != 0) {
print $f;
return resc($i-1, $f);
} else {
print $f;
}
}
resc(4, rand(0, 1));
?>
If you just want to print a bunch of random ints:
function resc_int($recursions, callable $func, $args = array()) {
for($i = 0; $i < $recursions; $i++) {
echo call_user_func_array($func, $args);
}
}
// resc_int(100, "rand", array(0, 1));
Completely untested. Caveat Lector.
The way this works is that instead of using recursion (which will use more and more memory the more recursions you have, as you can't garbage collect something with active references or you will get a segmentation fault later in PHP if it tries to access it), it uses iteration.
There's two kinds of "looping" in a sense.
Looping/Recursion.
Technically Recursion is a loop, as you continue recursing until you reach a stop condition (else you get an infinite loop, which is bad for fairly painful reasons). The loop construct in PHP is while().
Iteration
In pretty much every single case (unless you have a really good reason) this is always the better choice when you need something that loops. Iteration is, to put it simply, counting up or down to a target integer. This is the for() construct; and hence, also the foreach() construct, which uses the number of elements in an array as a target integer and then counts towards it, picking elements out of the array as it goes.
This is more memory efficient, and is remarkably easy to work with in PHP. It can also infinite loop, like while can (just give it an impossible condition to work towards), so watch out for that.
In short: have fun with the standard library (pretty much every function you regularly need is somewhere in there), and remember that recursion is your last option, not the first.
function resc($times, $cbFtn, Array $cbFtnArgs = array()) {
if ($times != 0) {
print call_user_func_array($cbFtn, $cbFtnArgs);
resc($times - 1, $cbFtn, $cbFtnArgs);
}
}
resc(4, 'rand', array(0, 1));
`I have a function called lets say calculate; what i want to do is run some loops with in the function calculating an outcome. at times this function does fail as it will get stuck in a loop, so iv got it covered to exit the loop but my problem is i want to restart this function and hope it come out with an outcome if not i will try again... on average the request does not have an outcome around 1 in 20, i need to restart the function from a clean slate.
i have tried to unset all the vars before i rerun the process with out success.please note this function will fail at times from the information handed to the process, un avoidable so
when this accurs i just want to rerun the function automatically to generate an outcome.
http://www.gamezslave.com/test/DynamicSlots.swf this is my test prototype give you an idea
sometimes you refresh it will error because of this factor.
<?php
$checker = 0; // if i cant get a result i could use this will tick up until condition
function shuffleArray($myArray) {
$value_count = array_count_values($myArray);
$last_value = $myArray[count($myArray) - 1];
unset($myArray[count($myArray) - 1]);
$shuffle = array();
$last = false;
while (count($myArray) > 0) {
$keys = array_keys($myArray);
$i = round(rand(0, count($keys) - 1));
while ($last === $myArray[$keys[$i]] ) {
$i = round(rand(0, count($keys) - 1));
echo "stuck";
$checker++;
if($checker>10){
echo " Too many checks so die, and restart process ";
return false;
bob; // this is the check function to goto and restart
}
}
$shuffle[] = $myArray[$keys[$i]];
$last = $myArray[$keys[$i]];
unset($myArray[$keys[$i]]);
}
if ($last_value === $last) {
$i = 0;
foreach($shuffle as $key=>$value) {
if ($value !== $last_value) {
$i = $key;
break;
}
}
array_slice($shuffle, $i + 1, 0, $last_value);
} else {
$shuffle[] = $last_value;
}
return $shuffle;
}
print_r(shuffleArray(array(1,5,5,3,7,7,7,7))); // just a example
function bob(){
if($checker>10){
$checker = 0;
shuffleArray();
echo "bob";
reset($myArray); // thought this may clean/reset the array i couldnt use
}
}
The idea this shuffle returns that no two symbols elemts of the same will be next to each other but sometimes at the end of the array as its shuffling randomly im left with bad odds (apple, orange, orange, orange) so what i need to do is resart this process again from start take in mind there is about 10 different item in the array and duplicates of each for example 10 apples ,10 oranges 4 bannanas 3 grapes sometimes the shuffle manages to generate an outcome where im stuck with too many of the same item at the end of the array wich then i need to rerun the script(and this bit is the problem) i dont know how.
Are you using globals?
If yes: Stop that. It's terrible practice. Seriously. There's never a reason to use globals with any sort of sane code.
If no: There's nothing to do. Each function invocation is a clean slate.
EDIT After seeing the code, I'm kinda speechless.
http://us3.php.net/manual/en/function.shuffle.php
I would set defaults to all variables inside of your function, and pass anything active as a parameter. Then use a set of return codes to indicate success or failure, or validate the outcome in some way and re-run.
I'm agreeing with Tyler Eaves here and i wanted to add as another reply a very important topic in programming:
A function "should" in theory be as scalar as possible meaning that it should not affect the outside world and should return the same information everytime for the same parameters.
If you call a function with parameter X, Y and Z and call it again while your system is in the same state, the function should return the exact same result.
But if a function is not scalar (Virtual for instance), such as dependant on external data (files, database rows or single instance accessible class data) then you should theorically not affect that external data from this function or else calling the function multiple times yield different results...
I've been trying to present my data from my database using PHP. My while loops keep running.
function makeCollection(){
$images = mysql_query("select file_id from images where collection_id = 1");
//returns file_id
$fileIds = mysql_fetch_array($images, MYSQL_NUM );
//get file ids from $images into array
while($fileIds != false){
echo($fileIds[0]);
}
}
I have three objects that fit with id = 1, 2, and 3 (it's on auto-increment). Shouldn't the loop iterate through then stop after the third? It just write '1' for infinity.
You need to call the function within the loop condition so it can be evaluated multiple times. Right now you just call it only once, that's going to tell PHP to fetch only the first row. If it's not false (i.e. MySQL returned at least one row), your while loop will be infinite.
while (($fileIds = mysql_fetch_array($images, MYSQL_NUM )) !== false) {
echo $fileIds[0];
}
By calling it every time the loop condition is checked, PHP internally advances the result set pointer so it can cover all rows in the result set. Eventually this function will return false and terminate the loop.
while($fileIds != false){
echo($fileIds[0]);
}
You're not doing anything to advance the loop field inside the loop. You have a line immediately before the loop which sets $fileIds, but as things stand, it only ever gets called once because it is outside the loop.
What you need is to put that inside the loop, probably inside the while() itself, as follows:
while(($fileIds = mysql_fetch_array($images, MYSQL_NUM)) !== false) {
....
}
Hope that helps.
I have a function that generates a key of 4 characters that has to be unique for each time. In order to do that, the function first generates a key, and then checks a database table to see if it's in use by someone else.
If it's not in use, it returns the key, else, it calls itself again, but this causes the function to do an infinite loop, which is a no-no. Here's the whole function:
function key_generator($length = 4)
{
// I've subsequently left out the generating code,
// which is not necesarry in this case
$key = 'xxxx';
if ($this->user_model->valid_key($key) == true)
{
return $key;
}
else
{
$this->key_generator(4);
}
}
What is the correct way to call the function again?
By the way, I'm using CodeIgniter, hence $this.
I would not use recursive functions for retry-scenarios (since you don't reuse the result of the function, it's pointless to use recursion)... It adds a lot of unnecessary overhead. Do something like this:
do {
$key = ...; // Generate your key here...
} while (!$this->user_model->valid_key($key));
return $key;
If you're near the maximum number of keys, this will result in very long loop times, so you might want to put some kind of max limit.
Oh, and if this is occurring on multiple threads simultaneously and you're checking a database, you should implement table write locking so that the same key can't be inserted twice. Preferably the function that checks whether a key is available should lock, check, and if available write in the same transaction to avoid any collisions.
You need to return the result of the self-call, otherwise the valid key won't get returned once it recurses.
return $this->key_generator($length);
but this causes the function to do an infinite loop,
If you absolutely want to keep your recursive strategy you have to define an end case. For example you may define a counter, like this:
function key_generator($length = 4, $limit=5)
{
if($limit === 0) {
throw new YourException();
}
// I've subsequently left out the generating code,
// which is not necesarry in this case
$key = 'xxxx';
if ($this->user_model->valid_key($key) == true)
{
return $key;
}
else
{
return $this->key_generator(4, ($limit-1));
}
}
It is however also possible to do your code iteratively...
If you include enough uniqueness in your key generation routine, you might be able to avoid this situation in the first place. E.g. have the routine take into account the current timestamp and the local hostname and/or PID.
Looping in such a non-deterministic fashion is generally proof of some part being too naive. That's not good. :-)
Anyhow, it would at least be good practice to catch it and log some sort of error as opposed to hanging the request and finally timing out:
function key_generator($length = 4)
{
/* The $attempts_left clearly depends on how much trust
you give your key generation code combined with the key space size. */
$attempts_left = pow(16, $length) * 2;
/* ... just guessing, in case your key base is 16, i.e. [0-9a-z] for example */
do {
// ... key generation goes here ...
$key = 'xxxx';
} while ( $this->user_model->valid_key($key) == false && $attempts_left-- > 0 );
if( $attempts_left < 1 )
return false;
else
return $key;
}
Why don't you just scan the key value space for the first unused key? Needs the key to fulfill additional constraints on top of being four characters long and unique?
You could remember the last returned key to resume scanning from there on subsequent calls.
If you want subsequent calls not to return similar keys, you could shuffle your key database first. This would mean that you need to hold a 456976, 1679616, 7311616, or 14776336 element array somewhere (depending on whether the alphabet used are single- or double-cased characters, with or without digits).
You could put your code into a loop and determine the key iteratively instead of
recursively.
Example:
function key_generator($length = 4)
{
do {
$key = 'xxxx'; //TODO
if (timeOutReached()) return InvalidKey;
} while (!$this->user_model->valid_key($key))
return $key;
}
The loop itself does not prevent an infinte loop, but unlike a function call, this doesn't eat up stack space, so you don't risk a stack overflow.
Also it simplifies things a little bit. Depending on the type of the key you can also adapt the key generation method, for example with numbered keys you can increase exponentially with each iteration.
Remarks: If it is possible, use a database's auto-increment feature instead of rolling your own key generation feature.
Also make sure you protect your code against concurrent access. What if two instances of this function try to generate a key and they both determine the same? Use critical sections or transactions to make sure nothing bad happens.
Using a function inside itself
function test($val) {
/*initialize return value by using the conditions*/
if($val>=5){
/*do something with return statement*/
return $val+10;
} else {
/*set the return default value for avoid the error throwing*/
return "default value";
}
/*return the function used for check the condition*/
return test($val);
}
echo test(4); // output "default value";
echo test(6); //output 16