jquery dynamic url - php

I have a form and the url for submitting the form will generated dynamicly
var Var1 = new Array();
var Var2 = new Array();
if(Var1.length === 0)
$(this).attr('action', 'http://localhost/Method' ).submit();
if(Var1.length != 0 && Var2.length === 0)
$(this).attr('action', 'http://localhost/Method/Var1').submit();
if(Var1.length != 0 && Var2.length != 0)
$(this).attr('action', 'http://localhost/Method/Var1/Var2').submit();
and all that URLs fires one method in the server and it is
public function Method(){}
public function Method(Var1){}
public function Method(Var1 , Var2){}
is there anyway to make all the last 3 methods as one method? something like this:
public function Method(Var1, Var2){
if( condition for Var1 ){// doSomthing}
if( condition for Var2 ){// doSomthing}
}

If you need this function for PHP, you can use func_get_arg and func_num_args:
public function Method() {
$numArguments = func_num_args();
if ($numArguments >= 1) {
$argument1 = func_get_arg(0);
// Do something with argument 1
}
if ($numArguments >= 2) {
$argument2 = func_get_arg(1);
// Do something with argument 2
}
}

If all the three url calls a single method in your server you can use the default argument mechanism.
public function Method($Var1=null, $Var2=null){
if(is_null($Var1)){// doSomthing}
if(is_null($Var2)){// doSomthing}
}
Obviously to map these urls you need to use some sorts of router logic. And the router must dispatch the proper method of the object.
For exmaple if your url is something like /index.php/Object/method/param1/param2, index.php should create the proper object first.
$parts = explode('/', $_SERVER['REQEUST_URI']);
array_shift($parts); // emtpy part
array_shift($parts); // index.php
$cls = array_shift($parts) // Object
$obj = new $cls;
And then dispatch the method.
$method = array_shift($parts);
call_user_func_array(array($obj, $method), $parts);

public function Method(){
$root = 'http://localhost/Method/',
$Var1 = func_get_args(0) || '',
$Var2 = func_get_args(1) || '';
if($Var1 && $Var2) $root .= $Var1 + '/' + $Var2;
else if($Var1 && !$Var2) $root .= '/' + $Var1;
}

Related

Optional parameters in PHP function without considering order

Is there a way in PHP to use a function which has optional parameters in its declaration where I do not have to pass an optional arguments which already have values declared and just pass the next argument(s) which have different values that are further down the parameter list.
Assuming I have a function that has 4 arguments, 2 mandatory, 2 optional. I don't want to use null values for the optional arguments. In usage, there are cases where I want to use the function and the value of the 3rd argument is the same as the default value but the value of the 4th argument is different.
I am looking for a not so verbose solution that allows me to just pass the argument that differs from the default value without considering the order in the function declaration.
createUrl($host, $path, $protocol='http', $port = 80) {
//doSomething
return $protocol.'://'.$host.':'.$port.'/'.$path;
}
I find myself repeating declaring variables so that I could use a function i.e to use $port, I redeclare $protocol with the default value outside the function scope i.e
$protocol = "http";
$port = 8080;
Is there any way to pass the 2nd optional parameter($port) without passing $protocol and it would "automatically" fill in the default value of $protocol i.e
getHttpUrl($server, $path, $port);
This is possible in some languages like Dart in the form of Named Optional parameters.See usage in this SO thread. Is their a similar solution in PHP
You could potentially use a variadic function for this.
Example:
<?php
function myFunc(...$args){
$sum = 0;
foreach ($args as $arg) {
$sum += $arg;
}
return $sum;
}
Documentation:
http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list
PHP doesn't allow at this state to call functions parameters in the order we want.Maybe in the future it will.However you can easily achieve your purpose by using an associative array as the only argument, and then define, the default parameter in the function.For the call you will need to pass an array with only the values which interest you.This array will be merged with the default array.You can even implement required parameters and call them in any order you want.
example:
function mysweetcode($argument){
$required=['first'];//specify required parameters here
$default=['first'=>0,'second'=>1,'third'=>2];//define all parameters with their default values here
$missing=[];
if(!is_array($argument)) return false;
$argument=array_intersect_key($argument,$default);
foreach($required as $k=>$v){//check for missing required parameters
if(!isset($argument[$v]))
$missing[]=$v;
}
if(!empty($missing)){// if required are missing trigger or throw error according to the PHP version
$cm=count($missing);
if (version_compare(PHP_VERSION, '7.0.0') < 0) {
trigger_error(call_user_func_array('sprintf',
array_merge(array('Required '.(($cm>1)?'parameters:':'parameter:').
str_repeat('%s,',$cm).(($cm>1)?' are':' is').' missing'),$missing)),
E_USER_ERROR);
}else{
throw new Error(call_user_func_array('sprintf',array_merge(
array('Required '.(($cm>1)?'parameters:':'parameter:').
str_repeat('%s',$cm).(($cm>1)?' are':' is').' missing'),$missing)));
}
}
$default=array_merge($default,$argument);//assign given values to parameters
extract($default);/*extract the parameters to allow further checking
and other operations in the function or method*/
unset($required,$missing,$argument,$default,$k,$v);//gain some space
//then you can use $first,$second,$third in your code
return $first+$second+$third;
}
var_dump(mysweetcode(['first'=>9,'third'=>8]));//the output is 18
var_dump(mysweetcode(['third'=>8]));//this throws Error on PHP7 and trigger fatal error on PHP5
You can check a live working code here
Well, this should work:
function myFunc($arg1, $arg2, $arg3=null, $arg4= null){
if ( is_null( $arg3 ) && is_null( $arg4 ) {
$arg3 = 3;
$arg4 = 4;
} else if ( is_null( $arg4 ) ) {
$arg4 = $arg3;
$arg3 = 3;
}
echo $arg1 + $arg2 + $arg3 + $arg4;
}
However I suggest you to rethink your problem (as a whole) because this is not a very good idea.
You could refactor this to use a parameter object; this way, you could include the default parameters in this object and set them in any order (with a trade-off of more verbose code). As an example using your above code,
<?php
class AdditionParameters
{
private $arg1 = 0;
private $arg2 = 0;
private $arg3 = 3;
private $arg4 = 4;
public function getArg1() { return $this->arg1; }
public function getArg2() { return $this->arg2; }
public function getArg3() { return $this->arg3; }
public function getArg4() { return $this->arg4; }
public function setArg1($value) { $this->arg1 = $value; return $this; }
public function setArg2($value) { $this->arg2 = $value; return $this; }
public function setArg3($value) { $this->arg3 = $value; return $this; }
public function setArg4($value) { $this->arg4 = $value; return $this; }
}
From there, you could simply call the function while passing in this new object.
function myFunc(AdditionParameters $request) {
return $request->getArg1()
+ $request->getArg2()
+ $request->getArg3()
+ $request->getArg4();
}
echo myFunc((new AdditionParameters)->setArg1(1)->setArg2(2)->setArg4(6));
// or echo myFunc((new AdditionParameters)->setArg1(1)->setArg4(6)->setArg2(2));
Otherwise, PHP doesn't allow you to have named optional parameters. (e.g. myFunc(1, 2, DEFAULT, 4);)
You have the response in your question, you can declare your function like
function myFunc($arg1, $arg2, $arg3 = null, $arg4 = null){
//here you check if the $arg3 and $arg4 are null
}
then you call your function using
myFunc($arg1, $arg2);
There is no such way in PHP(like in python for example).
You have to use some tricks in order to do that but will not always work.
For example:
// creates instances of a class with $properties.
// if $times is bigger than 1 an array of instances will be returned instead.(this is just an example function)
function getInstance($class, $properties = [], $times = 1){
//my code
}
$user = getInstance("User", ["name" => "John"]); // get one instance
$users = getInstance("User", ["name" => "John"],2); // get two instances.
If you want to use the function without passing the $parameters argument, like this:
$users = getInstance("User",2);
you can change the function to:
// creates instances of a class with $properties.
// if times is bigger than 1 an array of instances will be returned instead.
function getInstance($class, $properties = [], $times = 1){
if(is_numberic($properties)){
$times = $properties;
$properties = [];
}
//my code
}
Of course, this strategy will work only if you parameters have different types.
PS. This method is use in the Laravel Framework a lot. From there I got the inspiration.
This is modified from one of the answers and allows arguments to be added in any order using associative arrays for the optional arguments
function createUrl($host, $path, $argument = []){
$optionalArgs = [
'protocol'=>'http',
'port'=>80];
if( !is_array ($argument) ) return false;
$argument = array_intersect_key($argument,$optionalArgs);
$optionalArgs = array_merge($optionalArgs,$argument);
extract($optionalArgs);
return $protocol.'://'.$host.':'.$port.'/'.$path;
}
//No arguments with function call
echo createUrl ("www.example.com",'no-arguments');
// returns http://www.example.com:80/no-arguments
$argList=['port'=>9000];
//using port argument only
echo createUrl ("www.example.com",'one-args', $argList);
//returns http://www.example.com:9000/one-args
//Use of both parameters as arguments. Order does not matter
$argList2 = ['port'=>8080,'protocol'=>'ftp'];
echo createUrl ("www.example.com",'two-args-no-order', $argList2);
//returns ftp://www.example.com:8080/two-args-no-order
As of version 8.0, PHP now has named arguments. If you name the arguments when calling the function, you can pass them in any order and you can skip earlier default values without having to explicitly pass a value for them.
For example:
function createUrl($host, $path, $protocol = 'http', $port = 80)
{
return "$protocol://$host:$port/$path";
}
createUrl(host: 'example.com', path: 'foo/bar', port: 8080);
// returns: "http://example.com:8080/foo/bar"

call_user_func how to solve this error

How to solve this problem with call_user_func
When I call the function I have this error generated by php. Below the error.
Warning: call_user_func() expects parameter 1 to be a valid callback, function 'getChildsInMenuCount' not found or invalid function name i
the line inside my files with the function
while ($Qcategories->fetch() ) {
$categories_count++;
$rows++;
if ((!isset($_GET['cID']) && !isset($_GET['pID']) || (isset($_GET['cID']) && ((int)$_GET['cID'] === $Qcategories->valueInt('id')))) && !isset($cInfo) && (substr($action, 0, 3) != 'new')) {
$category_childs = ['childs_count' => AdministratorMenu::getChildsInMenuCount($Qcategories->valueInt('id'))];
$cInfo_array = array_merge($Qcategories->toArray(), $category_childs);
$cInfo = new objectInfo($cInfo_array);
}
The result of var_dump(__FUNCTION__); is string(20)"getChildsInMenuCount"
class AdministratorMenu {
// Count how many subcategories exist in a category
public static function getChildsInMenuCount($id) {
$OSCOM_Db = Registry::get('Db');
$categories_count = 0;
$Qcategories = $OSCOM_Db->prepare('select id
from :table_administrator_menu
where parent_id = :parent_id
');
$Qcategories->bindInt(':parent_id', $id );
$Qcategories->execute();
while ($Qcategories->fetch() !== false) {
$categories_count++;
$categories_count += call_user_func(__FUNCTION__, $Qcategories->valueInt('id'));
}
return $categories_count;
}
}
Since it's a class method, you need to use __METHOD__, not __FUNCTION__. This will include the class prefix.
$categories_count += call_user_func(__METHOD__, $Qcategories->valueInt('id'));
change call_user_func parameters like below:
call_user_func(__CLASS__ . '::' . __FUNCTION__, $Qcategories->valueInt('id'));
You must also specify the class in first parameter of call_user_func

How Can we pass function parameter as another function which itself has different parameters?

I have function below :
function cache_activity_data($cid,$somefunction) {
$cache_time = '+15 minutes';
$cache_id = $cid;
$expire = strtotime($cache_time);
$cache = cache_get($cache_id);
if (!empty($cache->data)) {
if (time() > $cache->expire) {
cache_clear_all($cache_id, 'cache_custom_activity_dashboard');
$report = $somefunction; // will get from function
cache_set($cache_id, $report, 'cache_custom_activity_dashboard', $expire);
}
else {
$report = $cache->data;
}
}
else {
$report = $somefunction; // will get from function
cache_set($cache_id, $report, 'cache_custom_activity_dashboard', $expire);
}
return $report;
}
Now $somefunction can be like below examples :
total_comments_per_user($user->uid);
total_comments_per_user_time_limit($user->uid, $user_year_start);
total_revisions_time_limit($month_ago);
total_revisions_time_limit($year_start);
every time I need to pass like 20 different functions. Is that possible I am getting error as at place of varibales I am passing function But I am not able to figure is that possible.
How I want to use :
//want to write this as function
$cache_revisions_total = cache_get("total_revisions", "cache_custom_activity_dashboard");
if (!empty($cache_revisions_total->data)) {
if (time() > $cache_revisions_total->expire) {
cache_clear_all("total_revisions", 'cache_custom_activity_dashboard');
$t_revisions = total_revisions();
cache_set("total_revisions", $t_revisions, 'cache_custom_activity_dashboard', $expire);
}
else {
$t_revisions = $cache_revisions_total->data;
}
}
else {
$t_revisions = total_revisions();
cache_set("total_revisions", $t_revisions, 'cache_custom_activity_dashboard', $expire);
}
// want to write this as function end here
$vars['total_bubbla_rev'] = number_format(($t_revisions / $days_from_rev_start), 2, '.', '');
// here i want to do same so i need to write function or should i repeat code
$y_revisions = total_revisions_time_limit($year_start);
$vars['yearly_bubbla_rev'] = number_format(($y_revisions / $year_days), 2, '.', '');
// here i want to do same so i need to write function or should i repeat code
$m_revisions = total_revisions_time_limit($month_ago);
$vars['monthly_bubbla_rev'] = number_format(($m_revisions / 30), 2, '.', '');
Please suggest, Thanks!
I see two possible options.
Option 1
You could use Anonymous functions. I simplified your function but you'll get the idea:
function cache_activity_data($cid, $somefunction) {
$report = $somefunction();
}
Define your functions as anonymous functions:
$parm1 = "banana";
$parm2 = "fruit";
$your_function1 = function() use ($parm1, $parm2) {
echo "$parm1 is a $parm2";
};
$your_function2 = function() use ($parm1) {
echo $parm1;
};
Usage:
cache_activity_data($cid, $your_function1); // shows "banana is a fruit"
cache_activity_data($cid, $your_function2); // shows "banana"
Read carefully through the documentation. Especially the part about variable scopes.
Option 2
Another possibility is call_user_func_array() but this requires you to make a little adjustment to cache_activity_data(). You need to add a third parameter which holds an array:
function cache_activity_data($cid, $somefunction, $somefunction_parms) {
$report = call_user_func_array($somefunction, $somefunction_parms);
}
Define your functions as usual:
function your_function1($parm1, $parm2) {
echo "$parm1 is a $parm2";
}
function your_function2($parm) {
echo $parm;
}
Usage
cache_activity_data($cid, "your_function1", array("banana", "fruit")); // shows "banana is a fruit"
cache_activity_data($cid, "your_function2", array("banana")); // shows "banana"
First, you cannot pass functions as parameters, however you can use callbacks as explained here:
http://php.net/manual/en/language.types.callable.php
But in your case, this seems irrelevant as you are not determining the function or changing its value in cache_activity_data().
Therefore, you might want to do like this:
$reportDefault = total_comments_per_user($user->uid);
// Or ... $reportDefault = total_revisions_time_limit, total_comments_per_user_time_limit, etc..
$report = cache_activity_data($cid, $reportDefault);
You do not need to add pass $report or any function as parameter.

PHP: how to resolve a dynamic property of an object that is multiple levels deep

I am have written a helper function to "cleanup" callback variables for input into MySQL. This is the function that I wrote:
public function string($object, $objectPath) {
if (!empty($object->$objectPath) || $object->$objectPath !== '') {
$value = $object->$objectPath;
} else {
return 'NULL';
}
if (!empty($value) || $value != '') {
return "'".str_replace("'","''",$value)."'";
} else {
return 'NULL';
}
}
Now, $object is always an object returned by the call, and $objectPath is always a string to points to a given value. Here's where the problem comes in. This works:
$value = $this->db->string($object, 'foo');
However, this does not work:
$value = $this->db->string($object, 'foo->bar->foo1->bar1');
Whenever $objectPath is more than "one layer" deep, I get the following error from (Amazon's) client library:
Fatal error: Call to undefined method MarketplaceWebServiceOrders_Model_Order::getFoo->Bar() in /path/to/Model.php on line 63
The code block that the error refers to is this:
public function __get($propertyName)
{
$getter = "get$propertyName";
return $this->$getter(); // this is line 63
}
$object is not XML, so I can't use SimpleXMLElement and XPath.
What is the problem with my code? Is it that am I concatenating an object and a string? If so, how can I make that possible? How can I get this function to do what I intended it to do?
By the way, I'm using PHP 5.4.27.
PHP doesn't automatically resolve a string containing multiple path levels to children of an object like you are attempting to do.
This will not work even if $obj contains the child hierarchy you are expecting:
$obj = ...;
$path = 'level1->level2->level3';
echo $obj->$path; // WRONG!
You would need to split up the path and "walk" through the object trying to resolve the final property.
Here is an example based on yours:
<?php
$obj = new stdClass();
$obj->name = 'Fred';
$obj->job = new stdClass();
$obj->job->position = 'Janitor';
$obj->job->years = 4;
print_r($obj);
echo 'Years in current job: '.string($obj, 'job->years').PHP_EOL;
function string($obj, $path_str)
{
$val = null;
$path = preg_split('/->/', $path_str);
$node = $obj;
while (($prop = array_shift($path)) !== null) {
if (!is_object($obj) || !property_exists($node, $prop)) {
$val = null;
break;
}
$val = $node->$prop;
// TODO: Insert any logic here for cleaning up $val
$node = $node->$prop;
}
return $val;
}
Here it is working: http://3v4l.org/9L4gc
With #itsmejodie's help, I finally got a working solution:
public function string($node, $objectPath) {
$value = NULL;
$path = explode('->', $objectPath);
while (($prop = array_shift($path)) !== NULL) {
if (!$node->$prop) {
break;
}
$value = $node->$prop;
$node = $node->$prop;
}
if (is_string($value)) {
return "'".str_replace("'","''",$value)."'";
} else {
return 'NULL';
}
}
The key for me was to see that, as #itsmejodie put it, "PHP doesn't automatically resolve a string containing multiple path levels to children of an object." In a string like, 'foo->bar->foo1->bar2', PHP won't convert the ->'s into the T_OBJECT_OPERATOR, thus appending a string to an object, e.g., $object->foo->bar->foo1->bar2, just won't work.

Dynamic method name

First of all sorry for the title, but i had no clue how i should name it.
Let's say i have it like that:
$lang = new lang;
$lang->setLanguage('en');
$string = $lang->get('Willkommen');
This would output Welcome for example.
But what i want is this:
$lang = new lang;
$lang->setLanguage->en
$string = $lang->get->Willkommen
As you thought, this should also output Welcome.
In order words, i want the same result, but without having to pass arguments to the instance.
I searched a long time now, but could not find out how i could do that.
Sounds like you're looking for the __get magic method.
class lang {
var $language = 'en';
function __get($prop) {
if ($prop == 'Willkommen') {
if ($this->language == 'en') return 'Welcome';
else if ($this->language == 'fr') return 'Bonjour';
}
}
function __set($prop, $val) {
if ($prop == 'language') $this->language = $val;
}
}
$lang = new lang();
echo $lang->Willkommen; // Prints "Welcome"
$lang->language = 'fr';
echo $lang->Willkommen; // Prints "Bonjour"
In php, dynamic access is with {} :
$key = 'Willkommen';
$lang->{$key};

Categories