Here is the code that I am going to use for solving my complicated issue, that I posted earlier.
Logic behind that is - on every iteration of the recursion, function should decrease $wa for $amount, that has been already proceeded, and calculate new $wa, to find new $amount, until system could not find the $amount in table that will be bigger then resulted $wa, and proceed it as last iteration.
Code is returning nothing, when trying to devel it, no errors, no echo. What am I doing wrong?
$wa = 0.001;
$address = $address;
function recursion($wa)
{
$resulte = db_select ('Credit_user','c')
->fields ('c')
->range(0,1)
->orderby('cr_ts', 'ASC')
->condition('c.affected','0','=')
->condition('c.amount','0','!=')
->execute();
foreach($resulte as $item) {
$code = $item->redeem_code;
global $code;
$amounte = $item->amount;
global $amounte;
$wai = $wa - $amounte;
global $wai;
if ($wai < 0){
echo "production code that should operate with different
variations of $amounte and $redeem on last iteration";
return;
}
elseif ($wai >= 0){ echo "production code
that should operate with different variations
of $amounte and $redeem on each iteration";
return;
} else {
function recursion($wa){
}
}
}}
echo $amounte;
echo "<br>";
Well at least this part is wrong
} else {
function recursion($wa){
}
Should be
} else {
return recursion($wa);
}
But the rest of this code is pretty messy, so....
For example, this logic
if ($wai < 0){
//...
}elseif ($wai >= 0){
//...
}else{
//not reachable
return recursion($wa);
}
is quite flawed. Because the else block is not reachable. In otherwords nothing satisfies the else condition because most values goes though the elseif which has 1 and 0 in it's range, and many things in PHP evaluate out to 1{true} or 0{false} because of PHP's loose typing.
UPDATE
You can test this condition for yourself
$tests = [
false,
-10,
1,
0,
[], ''
];
foreach($tests as $wai){
if ($wai < 0){
echo "1";
}elseif ($wai >= 0){
echo "2";
}else{
echo "3";
}
echo "\n";
}
Outputs
2
1
2
2
2
2
As you can see there is no #3 which comes from the else block which as I said is impossible to reach. Thus this function does no recursion, and therefor can return nothing from said non-existant recursion.
Test it online
Additionally:
$wai = $wa - $amounte;
global $wai;
Global must be declared first.
global $wai;
$wai = $wa - $amounte;
We can test this, by setting up a function scope.
function foo(){
$wai = 50;
global $wai;
echo $wai;
}
global $wai;
$wai = 100;
foo();
Now one would expect this to print 50, however it prints 100. It executes this way:
PHP parses and interprets the code
We declare global$wai outside the function
We set $wai to = 100 (assignment)
We call function foo
We set the local variable $wai = 50;
We then declare $wai as a global, and it inherits the value of the global $wai from the global scope (outside the function scope), which is a value of 100
Then we echo that value.
This is a very close approximation of your code, it's functionally equivalent Check it yourself
Now if you change the order
function foo(){
global $wai;
$wai = 50;
echo $wai;
}
global $wai;
$wai = 100;
foo();
It outputs 50 test this
Let's see, the echo functions need to be changed to return. Assuming the recursion worked, but it doesn't. One has to assume that at some point it goes thought one of the other 2 parts of that if condition that I pointed out. If it didn't do that we would have infinite recursion until PHP runs out of memory and crashes or the max execution time is hit. So we're agreed it has to go though those. Now how can it return anything from
return recursion($wa);
If both of the other returns are just return; or return null. By it's very nature if the next iteration of the function returns null back to our return from calling said function recursively, then that call must also return null.
echo "production code that should operate with different variations of $amounte and $redeem on last iteration";
return;
So
return "production code that should operate with different variations of $amounte and $redeem on last iteration";
In other words, it's pretty much all broken. Please don't take this the wrong way, I'm just pointing out what I see wrong. Everyone has to start somewhere learning to code, I have almost 8 years professional web design and PHP programing experience. But, I still remember what it was like learning and I still make plenty of mistakes.
I've pointed out fixes for what I could, but for things like the if logic there is no way for me to figure out what that logic was supposed to be. I can only point out where it falls apart.
Related
So I am running into an issue that I figured out how to fix, but I am very curious as to why. So here is a block of code
<?php
function test($attempt=1){
if ($attempt == 5){
echo "Done!";
}else{
echo 'recursion!';
test($attempt++);
}
}
$test = test();
Now this code should run the first time, check, go into the else statement then run test again but this time with $attempt++ until eventually it is == to 5 and then it will echo done and complete. However this does not work and it loops forever. However it can be fixed by assigning the variable to another variable immediately after entering the function like so
<?php
function test($attempt=1){
$nextAttempt = $attempt+1;
if ($attempt == 5){
echo "Done!";
}else{
echo 'recursion!';
test($nextAttempt);
}
}
$test = test();
Any ideas as to why this is?
You want pre-increment instead of post-increment of the variable. This will increment the variable $attempt before passing it as an argument to the function instead of after.
So basically you want test(++$attempt); instead of test($attempt++);.
Sandbox with working example: http://sandbox.onlinephpfunctions.com/code/c50731815588d55bd079e701f1c5dde9e7148696
http://php.net/manual/en/language.operators.increment.php
The operator ++ executes after the evaluation of the sentence, so you are executing the call to the function with the same value ever.
test($attempt++);
is the same than:
test($attempt);
$attempt = $attempt + 1
I am looking to return an integer with a value of 50 or value of 25. Is this the correct way to do this or should I create a variable $temp1=50 and $temp2=25 and return the variable instead of just returning 50 and 25.
function somefunction($length)
{
if ($length > 50)
{
return 50;
} else {
return 25;
}
}
Sorry if duplicate, I looked.
It is perfectly fine the way you're doing it. Assigning a value to a variable to only return it makes no sense really.
As a better version to your alternative, for some more complicated cases, where you'd eventually need to return a variable, you could use only one variable instead of two as you suggested. Something more like
function somefunction($length)
{
$myVar = 0;
if ($length > 50) {
$myVar = 50;
}
else {
$myVar = 25;
}
return $myVar;
}
It is not necessary to assign a variable before. Just write
return ($length > 50 ? 50 : 25);
Assigning to a variable before returning is pointless. You're returning a value. 50 is a perfectly good value by itself, it does not need to be assigned to a variable before being returned.
In other words: you're doing it right already.
It depends on what you want to do :
if you just want to return a constant or if you want to parameter this constant.
in a case of a constant, for readability, you can name them :
define('RETURN_CONSTANT_SUP',50);
define('RETURN_CONSTANT_INF',25);
function somefunction($length)
{
if ($length > RETURN_CONSTANT_SUP)
{
return RETURN_CONSTANT_SUP;
} else {
return RETURN_CONSTANT_INF;
}
}
So you do it the right way, you can just use constant if, one day, you want to reuse those values.
I'd say the problem with your function is less the return but the input.
Anyway, your question is a bit theoretic. Because both returning a constant integer value as well as a variable would work. It wouldn't even make much of a difference. See the following example:
function somefunction($length)
{
return 25 + 25 * ($length > 50);
}
The problem with the code is that you have written it only for these specific values. So not using a variable can be a sign that the code is limited. But less because of the return and more because of the flow.
function integer_top_cut_drop($value, $top, $default)
{
$value = (int) $value;
$top = (int) $top;
$default = (int) $default;
if ($value > $top)
{
return $top;
}
return $default;
}
As this function shows, there are no numbers in there, but only variables. It pretty much does what your existing function does, but everything is variable. The numbers with their constant values have been removed and are now being passed as parameters:
function somefunction($length)
{
return integer_top_cut_drop($length, 50, 25);
}
So you normally never are concerned whether your return a variable, a constant, some other kind of expression or another functions return value.
More important is, that your code does what it has to do and you do it in a useful way.
That could mean in your code that your function already is totally fine.
But consider you enable yourself that you can re-use common parts, e.g. like shown here with a new function. That might be a bit over the top for your example, but just to show the picture.
A function can preserve the logic, so you don't need to write that part more than once. It also reduces the size of the other parts of the code using that function.
There is no correct way to do this.
This question is about style and preferences and you won't be able to get a definitive answer.
Just use what you like best (unless you are working in a team of course, in which case you should adapt the team's coding styleguide).
I'm trying to edit my co-worker's code (he's on vacation and out of reach) and there is this if statement:
if($this->carrier() == 1 and $this->carrier() == 2) {
return 'V';
}
My hope is that he accidentally put "and" instead of "or" which could explain a bug I'm getting, but he knows much more about PHP than I do and I want to be sure that this is wrong instead of just counter intuitive.
Yes, since it's a function with potential side effects, it might be true.
For example:
function carrier() {
return $someValue++;
}
Yes. The carrier() method could increment whatever value it returns each time you call it.
There's a small chance it could, yes.
He's calling a function twice, and you've not included the text of that function. So that could be doing something we can't see, like counting the number of times it's been called by this process.
On the other hand, it's much more likely that it is indeed a typo.
It is possible. Here is a working example you can run.
class program
{
private $i = 1;
function carrier()
{
$this->i=$this->i+1;
return $this->i-1;
}
function run()
{
if ($this->carrier()==1 && $this->carrier()==2)
{
echo "works";
}
else
{
echo "doesnt work" . $i;
}
}
}
$prog = new Program();
$prog->run();
`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...
out of curiosity I'm wondering if there's a more elegant way to write the conditionals below? I can't see a shorter way of writing it but it feels pretty clunky, so any suggestions welcome!
// Check whether this page has any visuals
if (count($this->page->pagevisuals->find_all()) > 0)
{
// Ok to go ahead and assign
$visual = $this->page->pagevisuals->find_all();
}
// If this is a sub page, parent page may have visuals we can use
elseif (count($this->page->parent->pagevisuals->find_all()) > 0)
{
$visual = $this->page->parent->pagevisuals->find_all();
}
// If two levels deep, grandparent page might have visuals
elseif (count($this->page->parent->parent->pagevisuals->find_all()) > 0)
{
$visual = $this->page->parent->parent->pagevisuals->find_all();
}
You can write a loop instead:
$page = $this->page;
$visual = null;
while (!$visual && $page) {
$visual = $page->pagevisuals->find_all();
$page = $page->parent;
}
I believe this is equivalent, and will work no matter how many levels of parents/nesting you have.
You could assign $this->page to a variable and begin the statements with that, for a very slight improvement.
Alternatively, you could create nested ternary statements to assign $visual, but that's certainly not recommended practice.
A recursive approach:
function getVisuals($root) {
$visuals = $root->pagevisuals->find_all();
if(count($visuals) === 0 && isset($root->parent)) {
$visuals = getVisuals($root->parent);
}
return $visuals;
}
$visuals = getVisuals($this->page);
If you have control over whatever class $this->page is an instance of, then you can make it an instance method.
You could make a recursive method to get rid of those nasty conditionals. Also you're calling the find_all() method twice for every conditional branch which doubles the process time.
Here's an attempt at a recursive function (might not work though, recursive functions are always a bit tricky!). Beware of infinite loops.
<?php
$visual = $this->page->find_all_visuals();
class Page {
function find_all_visuals()
{
$found = $this->pagevisuals->find_all();
if (count($found) > 0) {
return $found;
} else if ($this->parent == null) {
return null;
} else {
return $this->parent->find_all_visuals();
}
}
}
?>
You might want make two changes in your code:
Ensure that getVisuals() returns an empty array instead of null in case there are no visuals
Consider making a null-object - a singleton page instance that has no visuals and has itself as a parent. It might have a method like isNull() so you can easily test if a given page is the null page.
If you make the two adjustments, most of the code concerning visuals will become easier to write and debug.
Getting all the visuals for two levels (I assume you don't want recursion):
$visuals = array_merge(
$this->page->pagevisuals->find_all(),
$this->page->parent->pagevisuals->find_all(),
$this->page->parent->parent->pagevisuals->find_all(),
);
Getting the visuals of the page OR of parent OR of grand parent:
($visuals = $this->page->pagevisuals->find_all()) ||
($visuals = $this->page->parent->pagevisuals->find_all()) ||
($visuals = $this->page->parent->parent->pagevisuals->find_all());
Recursive functions would be much simpler too (this is a method to add to the page object):
public function findRecursive(){
$my_visuals = $this->pagevisuals->find_all()
return $this->parent->isNull()?
$my_visuals
: array_merge($my_visuals, $this->parent->findRecursive());
}
$visual = $this->page->pagevisuals->find_all()
or $visual = $this->page->parent->pagevisuals->find_all()
or $visual = $this->page->parent->parent->pagevisuals->find_all();
What do you do if none of them match? In this code it will be set to the last one, which is not the same as what you did. (In your code $visual was not touched if none matched, in this code it will be set to zero. You could add or $visual = -1 or something similar.)
You can make a loop if you want to avoid all the ->parent, but you'll need some terminator.
$el = $this->page;
while(!$visual = $el->pagevisuals->find_all()) {
$el = $el->parent;
}
This could run forever if it never matches, but I don't know enough about your application to suggest a termination condition - you could add a counter, or something else.