PHP Pass a function as a parameter in another function [duplicate] - php

This question already has answers here:
Accept function as parameter in PHP
(9 answers)
Closed 1 year ago.
I have two functions - the first function is complex and it takes around 15 seconds to load as it fetches data from third parties. The second one is a normal function. To illustrate this is what I have
<?php
class ComplexFunctions{
public function complexFunctionOne($x){
// do something
}
}
?>
<?php
function SimpleFunction($y, $z){
if($y){
// if $y is true use variable z
}else{
//if $y is false don't use variable z
}
return $a;
}
$cf = new ComplexFunctions();
$input_y = 'Y';
$input_y = 'Z';
$output = SimpleFunction($input_y, $cf->complexFunctionOne($input_y);
?>
I need to run the complex function $y only when the first variable $y is true. If it isn't I don't want to run it.
Unfortunately, regardless of whether $y is true or false - $cf->complexFunctionOne($input_y) is still loaded in any condition. This could take a lot of useless time for something that I do not want unless it's called specifically.
One solution could be to call $cf->complexFunctionOne($input_y) inside teh simple function, however, I have a hand full of complex functions e.g. complexFunctionTwo and I only want to use depending on the circumstance rather than have a Switch/Case statement.

well in order to pass a function, you can just:
$output = SimpleFunction($input_y, function() use ($input_y, $cf){
return $cf->complexFunctionOne($input_y);
};
so then you just need:
function SimpleFunction($y, $z){
if($y){
// if $y is true use variable z
$a = $z();
}else{
//if $y is false don't use variable z
$a = ...;
}
return $a;
}
In this way you will "lazy load" the result of $z

Related

What does a variable in the right do in yield expression?

According to PHP documentation, a variable passed in ::send() method of generator class is assigned to yield keyword.
it makes sense in following statement :
$v = yield;
But what about the statements like :
$v = yield $a;
yield keyword is already assigned and it shall return the variable passed into. Then what does $a do?
I've tried to figure this out and searched many posts and questions but none of them explain this.
Answering by myself...
$v = yield $a;
meaning, first yield $a just as generally it does, then assign a variable passed by send() method to $v.
Still can't get clear explanation. But I think this is somewhat an answer of this matter.
Using send() will define $v, so if you use $v = yield $a; and before the iteration, you sent a value with send() it will yield the value which you sent it.
It can be hard to get your head around so here is an example, which creates two parts, the foreach iterator which loops over the generator and then on iteration 10 it sends a stop to the while loop. Then using getReturn gets the last value of the yield, like your $v in $v = yield $a;
<?php
$engine = function($callback) {
$i = 0;
while (true) {
$state = (yield $callback($i++));
if ($state == 'stop') {
return $i;
}
}
};
$generator = $engine(function($i) {
return $i;
});
foreach ($generator as $value) {
echo "{$generator->key()} = {$value}\n";
if ($generator->key() == 10) {
$generator->send('stop');
}
}
echo 'Stopped on: '.$generator->getReturn();
https://3v4l.org/dY8rV
Result:
0 = 0
1 = 1
2 = 2
3 = 3
4 = 4
5 = 5
6 = 6
7 = 7
8 = 8
9 = 9
10 = 10
Stopped on: 11
The yield keyword can be used for three things:
On its own, to return control temporarily to calling code. This is the basis of all the other uses.
With a value after (yield $foo), to pass a variable to calling code.
With an assignment before ($bar = yield), to receive a variable from calling code.
These are sort of similar to how you can use a function call:
On its own, like doSomething(), to pass control temporarily to the definition of doSomething.
With a parameter, like doSomething($foo), to pass a variable to the function.
With an assignment before, like $var = doSomething(), to receive a variable from the function.
You are hopefully quite familiar with writing $bar = doSomething($foo); to pass $foo to a function, and get $bar out afterwards. $bar = yield $foo is similar, but the value is passed "out" to the calling code, and the new value received back from that calling code afterwards.
$foo and $bar are not connected in any way, they are just the input and output of that particular yield. In the calling code, the $foo part of yield $foo or $bar = yield $foo can be accessed by calling ->next() or ->current() or getting the value in a foreach. The calling code then calls ->send() with some value which becomes the $bar in $bar = yield or $bar = yield $foo.

Passing by reference vs. passing by value

<?php
function sum($y) {
$y = $y + 5;
}
$x = 5;
sum($x);
echo $x;
?>
So I have this code. The questions are: What does it output? The answer: 5. How do I make it to output 10? The answer: sum(&$x).
The problem is that I don't understand why the answer to the first question is 5. When you make sum($x), shouldn't it replace the function with $x, so $x= 5+5=10? Why the answer is 5? I really don't understand. Someone explaind me something related to pointers and the adress, but I didn't understand. I never understood the concept of pointers, and I googled it and apparently there are no pointers in php, so I'm super confused. My friend said that a variable is formed of a value, and the memory adress of that value. Can someone explain me like I'm 5 years old why the answer is 5 and not 10? Please
Let's pretend $x is a piece of paper with 5 written on it.
function sum($y) {
$y = $y + 5;
}
Here $y is the value of what you have written. You add 5 to such value in your mind, but the note is left untouched.
function sum(&$y) {
$y = $y + 5;
}
With the reference operator (&$y), you pass the very paper to the function, and it overwrites what's written on it.
For primitive values like numbers, I wouldn't bother and always return the value you want:
function valuePlusFive($x) {
return $x + 5;
}
$x = 5;
$x = valuePlusFive($x);
This is not a very good explanation from theory point of view, but this should help you understand the concept:
when you declare function like this and then call it:
function ($argument) {...}
The argument you pass there is passed by value. This means that inside the scope of a function you will be working with a copy of an argument you passed. You can imagine that before the function is called the copy of argument has been made and inside the function you're working with the copy, while original remains untouched. Once the function is finished the copy is no more
However when you declare it like this:
function (&$argument) {...}
You are passing argument by reference, meaning that you are working directly with a variable you've passed. So in this case no copies are made, you took the argument from one place, put it inside the function and changed it.
In PHP, "The scope of a variable is the context within which it is defined." (according to the docs). So inside your function, $y (a copy of the value you passed in) is being operated on, but it is not returned by the function. So when the function ends, the value is no longer accessible outside the function.
If you want to pass the variable in by reference (similar to a pointer in C) then you can add a & like so:
function sum(&$y) {
$y = $y + 5;
}
Now when you call this code:
$x = 5;
sum($x);
echo $x;
it will output 10. Maybe a better way to do this would be to return a value from your function, and output that value:
function sum($y) {
return $y + 5;
}
$x = 5;
echo sum($x);

How to check if variable was passed by reference in PHP

Straightforward:
I want to write some code which tells if a variable was passed by reference or not.
For example:
<?php
function isReference($variable) {
//return TRUE if &$something was passed
//return FALSE if $something was passed
}
$text = 'Anything';
$a = isReference(&$text); //return TRUE
$b = isReference($test); //return FALSE
?>
For those who are curious - why do I need it?
Firstly I do not like to leave problems unsolved.
Secondly, I am currently enhancing by skills by writing an extension to mysqli, which would prepare statements similar to how PDO does. If anybody knows the difference between bindParam and bindValue in PDO, they know that it's a workaround of this question. I can just make two functions, but I wonder if it's possible with one.
Thanks in advance.
Here's a way to do it without using the debug_zval_dump function:
function isReference($variable) {
$variable = array($variable);
$arg = func_get_arg(0);
$isRef = isset($arg[0]) && $arg === array($variable[0]);
$variable = $variable[0];
return $isRef;
}
Note: there is only a single case when this will not work:
$text = array(&$text); // although i don't see why such a structure could be used
isReference($text); // will wrongly return false
Obviously you can bypass this limitation by using a random unique key (instead of 0).
You can use debug_zval_dump to dump a string representation of an internal zend value to output:
function isRef(&$val) {
ob_start();
debug_zval_dump(&$val);
$ret = ob_get_clean();
preg_match('~refcount\((\d+)\)~', $ret, $matches);
return $matches[1] - 4;
}
$var1 = 'Var1';
$var2 = &$var1; // passed by ref
if(isRef($var2)) echo 'Passed by ref';
But be aware of PHP - 5.4.
Simply checking for the default value seems to work fine in my tests. Obviously it wont work if $t is already set to 'x' but you could change the default value to something totally unlikely to workaround this:
function test(&$t='x'){
if($t!='x') $t = 2;
}
test(); echo $t; //outputs: null
test($t); echo $t; //outputs: 2

PHP: Correct use of return in function - use variable or use a number directly?

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).

Two different return types in PHP function [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Multiple returns from function
Is it possible to return 2 results in the same PHP function? One is an array, the other is an integer. Could someone give me an example?
function functest() {
return array(1, "two");
}
list($first,$second) = functest();
There's nothing stopping you from returning whatever type you like from a function. You can return a dictionary with multiple keys, or an array of mixed object types, or whatever. Anything you like.
$arr = array();
$arr[] = $some_object;
$arr[] = 3;
$arr["a_string"] = "foo";
return $arr;
You have several options to simulate multiple return values (the first two, however, are just a kind of wrapping of multiple values into one):
Return an array with the two values: return array($myInt, $myArr); (see e.g. parse_url().)
Create a dedicated wrapper object and return this: return new MyIntAndArrayWrapper($myInt, $myArr);
Add an "output argument" to the function signature: function myFunc(&$myIntRetVal) { ... return $myArr; } (see e.g. preg_match(..., &$matches).)
What about this?
function myfunction() {
//Calculate first result
$arrayresult=...
//Calculate second result
$intresult=...
//Move in with each other . don't be shy!
return array($arrayresult,$intresult)
}
and in the other code
$tmp=myfunction();
$arrayresult=$tmp[0];
$intresult=$tmp[1];
It's totally possible since PHP doesn't use strong typing. Just return the value you want in whatever type you want. A simple example:
function dual($type) {
if ($type === 'integer')
return 4711;
else
return 'foo';
}
You can use several functions on the caller side to see which type you got, for example: gettype, is_int, is_a.

Categories