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"
I am running into strange problem. I have following simple line in PHP
<?php
echo "Value = ".$this->language; //outputs Value = en
echo "<br>isset = ".isset($this->language); //Outputs isset =
echo "<br>Is empty = ".empty($this->language); //Outputs Is empty= 1
?>
Why is that the second line doesn't prints true or '1' and third line prints its empty, when its clear from first line that this->language is set and is not empty??
instead of 'echo' use var_dump.Will help you to understand the difference.
$language = 'en';
echo "Value = ".$language; //outputs Value = en
$isset = isset($language);
$empty = empty($language);
echo "<br>isset = ";;
var_dump($isset); //bool(true)
echo "<br>Is empty = ";
var_dump($empty); // bool(false)
Below Code Snippet should help you
If the Variable is declared as private in parent class it will not be available in the child class , it has to be either protected or private
class base {
// changed to protected
protected $language = 'en';
}
class child extends base {
public function spit(){
echo "Value = ".$this->language; //outputs Value = en
echo "<br>isset = ".isset($this->language); //Outputs isset =
echo "<br>Is empty = ".empty($this->language); //Outputs Is empty= 1
}
}
$ch = new child();
$ch->spit();
Explanation for isset() is as below.
isset($this->language) will always echo 'false'. because the isset() accepts VARIABLES as it's parameters, but in this case, $this->language is NOT a VARIABLE. it is a VALUE returned from the __get() method of the class. Thus the isset($this->language) expression will always equal 'false'.
Please refer http://php.net/manual/en/function.isset.php
Explanation for empty() is as below.
class Registry
{
//Definition goes here
}
$registry = new Registry();
$registry->empty = '';
$registry->notEmpty = 'not empty';
var_dump(empty($registry->empty)); // true, so far so good
var_dump(empty($registry->notEmpty)); // true, .. say what?
$tmp = $registry->notEmpty;
var_dump(empty($tmp)); // false as expected
The result for empty($registry->notEmpty) is a bit unexpected as the value is obviously set and non-empty. This is due to the fact that the empty() function uses __isset() magic function in these cases.
Please refer http://php.net/manual/en/function.empty.php
Actually, the code is very complex, the code I was working on with is built with Silverstripe. But i found a dirty workaround that will work on plain PHP as well.
in parent class, i created a method which checks if language is set, like this
public function isLanguageEmpty(){
return isset($this->language);
}
and in child class we can simply use $this->isLanguageEmpty()
But to understand what might be the actual problem, the comments in original post and the other answers will be helpful.
In javascript I can pass an object literal to an object as a parameter and if a value does not exist I can refer to a default value by coding the following;
this.title = params.title || false;
Is there a similar way to do this with PHP?
I am new to PHP and I can't seem to find an answer and if there is not an easy solution like javascript has, it seems pure crazy to me!!
Is the best way in PHP to use a ternary operator with a function call?
isset($params['title']) ? $params['title'] : false;
Thanks
Don't look for an exact equivalent, because PHP's boolean operators and array access mechanism are just too different to provide that. What you want is to provide default values for an argument:
function foo(array $params) {
$params += array('title' => false, ...);
echo $params['title'];
}
somethig like this $title = (isset($title) && $title !== '') ? $title : false;
Or using the empty function:
empty($params['title']) ? false : $params['title'];
$x = ($myvalue == 99) ? "x is 99": "x is not 99";
PHP one liner if ...
if ($myvalue == 99) {x is 99} else {x is not 99 //set value to false here}
<?php
class MyObject {
// Default value of object property
public $_title = null;
// Default value of argument (constructor)
public function __construct($title = null){
$this->_title = $title;
}
// Default value of argument (setter)
public function setTitle($title = null){
// Always validate arguments if you're serious about what you're doing
if(!is_null($title) and !is_string($title)){
trigger_error('$title should be a null or a string.', E_USER_WARNING);
return false;
}
$this->_title = $title;
return true;
}
} // class MyObject;
?>
This is how you do an object with default values. 3 ways in 1. You either default the property value in the class definition. Or you default it on the __construct assignment or in a specific setter setTitle.
But it all depends on the rest of your code. You need to forget JS in order to properly use PHP. This is a slightly stricter programming environment, even if very loose-typed. We have real classes in PHP, not imaginary function classes elephants that offer no IDE code-completion support like in JS.
I see there are about a hundred different questions on here for Creating default object from empty value. None of them really seem to help with my issue.
I am assigning a child object of the same class in a method. This triggers the Creating default object from empty value error.
class myClass {
function __construct($rootName, $allowHTML = false, $endTag = true) {
$this->rootElement = $rootName;
$this->elements = array();
$this->attributes = array();
$this->value = "";
$this->allowHTML = $allowHTML;
$this->endTag = $endTag;
$this->styles = array();
$this->childID = 0;
}
// ... OTHER METHODS HERE (ALL PROPERTIES DECLARED)
function assignElement(&$theElement) {
// Get the index.
$index = count($this->elements);
// Assign the element.
$this->elements[$index] = $theElement;
if (get_class($theElement) == get_class($this)) {
$this->elements[$index]->childID = $index;
}
// Return the node.
return $this->elements[$index];
}
}
The error occurs on $this->elements[$index]->childID = $index;. How do I handle this properly?
Seems like you are passing NULL to the assignElement. get_class called with no arguments or null as argument, returns class of the object where it is defined, so your if conditions is true for null values. You should use is_object first.
I would like to do something like this:
function readUser($aUser = loadDefaultUser()){
//doing read User
}
I find that it will display a error to me, how can I pass a function return as a default value? Thank you.
I would rather give a Null value for this argument and then call loadDefaultUser() in the body of the function. Something like this:
function readUser($aUser = NULL){
if(is_null($aUser)){
$aUser = loadDefaultUser();
}
//...
}
Yes, you can provide a default argument. However, the default argument "must be a constant expression, not (for example) a variable, a class member or a function call."
You can fake this behaviour by using some constant value for the default, then replacing it with the results of a function call when the function is invoked.
We'll use NULL, since that's a pretty typical "no value" value:
function readUser($aUser = NULL) {
if (is_null($aUser))
$aUser = loadDefaultUser();
// ... your code here
}
You can add a callback-parameter to your loadDefaultUser() function when it's finished it fires the callback function with the return/result. It's a bit like ajax-javascript callbacks.
function loadDefaultUser ( $callback )
{
$result = true;
return $callback($result);
}
function readUser($aUser = NULL){
if ($aUser === NULL){
$aUser = loadDefaultUser();
}
//do your stuff
}