Pass all arguments to another function - php

I have two functions like this:
function mysql_safe_query($format) {
$args = array_slice(func_get_args(),1);
$args = array_map('mysql_safe_string',$args);
$query = vsprintf($format,$args);
$result = mysql_query($query);
if($result === false) echo '<div class="mysql-error">',mysql_error(),'<br/>',$query,'</div>';
return $result;
}
function mysql_row_exists() {
$result = mysql_safe_query(func_get_args());
return mysql_num_rows($result) > 0;
}
The problem is that the second function won't work because it passes the args to the first one as an array, when it expects them as different parameters. Is there any way to get around this, preferably without modifying mysql_safe_query?

How about using:
$args = func_get_args();
call_user_func_array('mysql_safe_query', $args);

N.B. In PHP 5.6 you can now do this:
function mysql_row_exists(...$args) {
$result = mysql_safe_query(...$args);
return mysql_num_rows($result) > 0;
}
Also, for future readers, mysql_* is deprecated -- don't use those functions.

Depending on the situation, following might also work for you and might be a little faster.
function mysql_safe_query($format) {
$args = func_get_args();
$args = is_array($args[0]) ? $args[0] : $args; // remove extra container, if needed
// ...
Which now allows for both types of calling, but might be problematic if your first value is supposed to be an actual array, because it would be unpacked either way.
You could additionally check on the length of your root-array, so it might not be unpacked if if there are other elements, but as mentioned: It is not really that "clean" in general, but might be helpful and fast :-)

Related

How to avoid a really long list of function parameters in PHP?

My problem is that I have lots of functions with VERY long lists of function parameters such as this one:
function select_items($con,$type,$id_item,$item_timestamp,$item_source_url,$item_type,$item_status,$item_blogged_status,$item_viewcount,$item_language,$item_difficulty,$item_sharecount,$item_pincount,$item_commentcount,$item_mainpage,$item_image_width,$item_image_height,$item_image_color,$item_modtime,$order,$start,$limit,$keyword,$language,$id_author,$id_sub_category,$id_category,$id_tag,$id_user){ ... }
As you can see its super long and (of course) very hard to maintain. Sometimes I need all of the variables to construct a super complex sql query, but sometimes I just use 1 or 2 of them. Is there a way to avoid this colossal list of parameters? For example with some strict / special naming convention ?
So basically I need something like this:
$strictly_the_same_param_name="It's working!";
echo hello($strictly_the_same_param_name);
function hello() //<- no, or flexible list of variables
{
return $strictly_the_same_param_name; // but still able to recognize the incoming value
}
// outputs: It's working!
I thought about using $_GLOBALs / global or $_SESSIONs to solve this problem but it doesn't seems really professional to me. Or is it?
For a first step, as you said, sometimes you need to call the function with only 2 args, you can set default values to your arguments in the declaration of your function. This will allow you to call your function with only 2 args out of 25.
For example:
function foo($mandatory_arg1, $optional_arg = null, $opt_arg2 = "blog_post") {
// do something
}
In a second step, you can use, and especially for that case, arrays, it will be way more simple:
function foo(Array $params) {
// then here test your keys / values
}
In a third step, you can also use Variable-length argument lists (search in the page "..."):
function sum(...$numbers) {
$acc = 0;
foreach ($numbers as $n) {
$acc += $n;
}
return $acc;
}
But ultimately, I think you should use objects to handle such things ;)
You can try use ... token:
$strictly_the_same_param_name= ["It's working!"];
echo hello($strictly_the_same_param_name);
function hello(...$args) //<- no, or flexible list of variables
{
if ( is_array( $args ) {
$key = array_search( 'What you need', $args );
if ( $key !== false ) {
return $args[$key];
}
}
return 'Default value or something else';
}

Call specific parameter in function

While I've taught myself a great deal, today I have been struggling with an unexpected behaviour of calling parameters in a function.
Here's an example function:
public function example($foo = null, $bar = null) {
if ($foo) {
// Do something
}
if ($bar) {
// Do Something
}
}
Now if I write a call that looks like the following, I was expecting to call $bar (the second parameter) instantly, which is not the case - and it makes sense to me why.
$this->example($bar);
Is there a way to just call the second parameter without using the following?
$this->example(null, $bar);
Well, like was suggested by Darren and his example, you can use function func_get_args, but there isn't much difference, so you should use which one fits you.
Using func_get_args, though doesn't seem too comfortable, so what is the reason not to use direct params? Pick any value you want to use as indicator (null, false, 'barambam') and do something like this:
const ARGFALSE = 29292929299;
function foobar($f, $o, $o, $b, $a, $r){
if (!$f)// equivalent to $f != false
echo 'First arg should not be used.';
If (!$o == ARGFALSE)echo 'Second is taging along with the first';
foobar(false, ARGFALSE);
Still, in some (or most) cases you may do it backwards (another example):
function getUsers($type, $limit = false) { // or your default value. It can be almost anything.
$query = 'Select from users where type = ?';
If($limit){
$query .= ' limit ?';
return $result = Db::run($query, [$type, $limit]);
}else{
return $result = Db::run($query, [$type]);
}
}

Confused on PHP func_num_args() Function

Following a Tutorial I am struggling with an issue in a PHP function. I have some basic background on C# and Java and according to my knowledge this code shouldn't work since I am not passing any parameter in the add() function, but , surprisingly!, it works!
According to PHP Manual the func_num_args() Gets the number of arguments passed to the function.so how we can echo the result of the add() function while we are not passing any parameter in the function?! Also, if the function is for getting the number of arguments how we can use it to calculate the numbers?!
<?php
function add(){
$args = func_num_args();
$sum = 0;
$i = 0;
for($i; $i< $args; $i++ ){
is_int(func_num_args($i)) ? $sum+= func_num_args($i) : die('Use Only Numbers');
}
}
echo add(2,5,10,12);
?>
Thanks for your comments
Use func_get_args():
function add(){
if(!func_num_args())return 0;
$args = func_get_args();
$sum = 0;
foreach($args as $arg){
if(is_int($arg)){
$sum += $arg;
} else {
die('Use Only Numbers');
}
}
return $sum;
}
As I mentioned in comments for "no args" case:
func_num_args()s return value is 0. for-loop in your code will not work as of $i < $args simplifies to 0 < 0, which is false.
To prevet that, you may try to use:
if(!func_num_args()){
die('There are no args!');
}
Your line echo add(); will work anyway, because:
PHP has support for variable-length argument lists in user-defined
functions. This is really quite easy, using the func_num_args(),
func_get_arg(), and func_get_args() functions.
No special syntax is required, and argument lists may still be
explicitly provided with function definitions and will behave as
normal.
Use func_get_args()
func_num_args()s return value is 0. for-loop in your code will not work as of $i < $args simplifies to 0 < 0, which is false.
To prevet that, you may try to use:
if(!func_num_args()){
die('There are no args!');
}
I think you are confused because you know what function overloading is, but php does not support function overloading in this manner.
Please go through this link. It will really help you out of your confusion.
php function overloading

Return a loop in function php

Is it possible to return a loop? not the result but the loop it self.
I want to create a function in php. For example like this.
function myloop($sql){
$query = mysql_query($sql);
return while(mysql_fetch_assoc($query))
}
The reason i want to create this is for me to avoid repeating code. Anyone can help me? Thank you..
No, but you can simulate that with an Iterator for stable released PHP as of today. In PHP 5.5 there will be generators that is close, too.
$lazyQuery = new SqlResultItertor($sql);
foreach ($lazyQuery as $assoc) {
$assoc; # the result, one per row
}
BTW: PDO and MySqli offer this already out of the box (not lazy query, but the result is traversable), for mysql you need to write such an iterator-result object your own.
For some mysql_* functions related code, see this answer. However the general suggestion as of today is to use PDO or mysqli instead, those offer more out of the box. See How to successfully rewrite old mysql-php code with deprecated mysql_* functions?
No, you can't. You can pass a function to a function, though:
// The myloop function, with another name.
function query($sql, $rowcallback)
{
$query = mysqli_query($sql); // use mysqli, not mysql
while
( ($row = mysql_fetch_assoc($query)) &&
call_user_func($rowcallback, $row) );
}
// The code to process a row.
function processRow(array $row)
{
// Use your row here..
var_dump($row);
return true; // You can return false to break processing.
}
//calling:
query($yourSelf, 'processRow');
Instead of passing the function by name, you can also use anonymous functions, depending on your php version:
//calling:
query($yourSelf,
function(array $row)
{
var_dump($row);
return true; // You can return false to break processing.
});
The function which is called from the callee is often called a callback. call_user_func is the best way to call a callback, since it will also accept methods and static methods, not just functions, so you're more flexible.
No, it isn't.
You can return a function to does nothing but run a loop, but you can't return the loop itself.
No.
You could, for instance, return an anonymous function which may contain a loop, but you can only return values from functions, not language constructs.
You should turn it inside out!
Instead of returning the loop, you could do it this way using Variable functions :
function myloop($sql, $myFunction){
$query = mysql_query($sql);
while(mysql_fetch_assoc($query)) {
$myFunction($result);
}
}
function doSomethingWithTheResult($result) {
echo $result; // just to have something here...
}
//now the usage:
myloop("SELECT 1", 'doSomethingWithTheResult');
With a squint, this is similar to the concept of the Template method OOP design pattern.
No, but you could do
function loopdate($sql,$code)
{
$query=mysql_query($sql)
while (mysql_fetch_assoc($query))
{
eval($code);
}
}
However - eval is rediculously dangerous its really really discouraged.
function loopdate($sql,$function)
{
$query=mysql_query($sql)
while ($data=mysql_fetch_assoc($query))
{
$function($data);
}
}
would be better.
myfunc($data)
{
foreach ($data as $key->$value)
{
print "<tr><td>".$key."<td><td>".$value."</td></tr>\n";
}
}
So you can call
loopdate("select * from mytable","myfunc");
In PHP 5.5+ it is possible, using the yield keyword instead of return (this is called a generator):
function myloop($sql) {
$query = mysql_query($sql);
while (($row = mysql_fetch_assoc($query))) {
yield $row;
}
}
foreach (myloop('SELECT * FROM foo') as $row) {
// do something with $row
}
This is not much different from what you could do with iterators in older PHP, but the code is much cleaner.

Switching methods for a single result

I have a situation where I require to consult different objects in PHP via different methods to find some data.
The question regards more about formatting the code than an actual programming issue. What I am trying to do is not using several if's to gather this data like:
$data = obj->getData();
if (!isset($data)) $data = othObj->getThisData();
if (!isset($data)) $data = anothObj->getTheData();
if (!isset($data)) $data = anothOne->getAData();
...
process($data)
I was wondering what are the best practices in this case, if there is a better way using another procedures, like foreach or switch/case.
Thanks!
You can make an array of the possible objects you want to try, then run a loop. Might be more maintainable. This code can be modified to include parameters and use call_user_func_array instead.
$dataCallback = array(
array($othObj, 'getData'),
array($othObj, 'getThisData'),
array($anothObj, 'getTheData'),
array($anothOne, 'getAData'),
);
for($i = 0, $t = count($dataCallback); !isset($data) && $i < $t; $i++) {
$callback = $dataCallback[$i];
$data = call_user_func($callback);
}
if (isset($data))
process($data);
else
//no valid data returned at all ...
It doesn't look too bad the way it is.
It could be a bit more efficient if the if's were nested. e.g.
if (!isset($data = othObj->getData()))
if (!isset($data = othObj->getThisData()))
if (!isset($data = anothObj->getTheData()))
$data = anothOne->getAData()))
// ...
process($data)
Since there are less calls to isset (though they're pretty cheap anyway, so I wouldn't worry about it).
Personally I'd do something like this:
$data = null;
if (isset($obj->getData()) $data = $obj->getData();
else if (isset($othObj->getThisData()) $data = $othObj->getThisData();
else if (isset($anothObj->getTheData()) $data = $anothObj->getTheData();
else if (isset($anothOne->getAData()) $data = $anothOne->getAData();
process($data)
This saves processing time if the earlier objects actually return something. Since it is an elseif setup once it finds data it'll stop processing the other if clauses.
I don't think a switch statement would be appropriate in this case. Switches tend to be testing the value of one variable (is $a = 1, 2, 3 or 4).
($data = $ob1->get()) || ($data = $ob2->get()) || ($data = $ob3->get());
Would work, but if you're get function returns an empty array or false or empty string instead of NULL, it's going to continue looking for data...
I'd probably group the objects to ask for data into an array:
$objArray = array($obj, $othObj, $anothObj, ... );
Then run through a while loop until I had data:
$i = 0;
do {
$data = $objArray[$i]->getData();
$i++;
} while(!isset($data) && $i < count($objArray));

Categories