This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
default method argument with class property?
I'm writing a recursive function and just for ease of use I want the first call of the function to accept a default argument. This value has to be the address of an object member variable. See below full code:
class Test{
public $hierarchy = array( );
public function addPath( $path, &$hierarchy ){
$dirs = explode( '/', $path );
if( count( $dirs ) == 1 ){
if( is_dir( $path ) )
$hierarchy[ $dirs[ 0 ] ] = '';
else
$hierarchy[ $path ] = '';
return $hierarchy;
}
$pop = array_shift( $dirs );
$hierarchy[ $pop ] = $this->addPath(
implode( '/', $dirs ), $hirearchy[ $pop ] );
return $hierarchy;
}
}
$t = new Test( );
$t->addPath( '_inc/test/sgsg', $t->hierarchy );
print_r( $t->hierarchy );
Now, what I would like to do here ideally is add a default value:
public function addPath( $path, &$hierarchy = $this->hierarchy ){
So that I can call it like this:
$t->addPath( '_inc/test/sgsg' );
But this gives me the following error:
Parse error: syntax error, unexpected '$this' (T_VARIABLE) in tst.php on line 9
I've been trying a few things with no success. Is there any way I can achieve this?
Unfortunately you cannot do this, the parser does not (cannot!) cater for resolving variables in function definitions.
You can however define the function with &$hierarchy = null in the definition and use is_null to see if a value was passed. (unless your referenced value will sometimes be null, then you'll need another workaround)
If is_null returns true then you can assign $hierarchy = &$this->hierarchy
After a quick discussion in PHP chat, using func_num_args() might be useful here. It doesn't count args that are populated with defaults, so you can safely pass variables that contain null by reference, and use this function to determine if the value in $hierarchy came from a passed parameter, or by the default. (thanks #NikiC)
Related
I have the function/method below inside a class that I'm creating and I'm just wondering what's the best way to handle empty/null arguments.
For example, in the following example, if I wanted to just set just the category when calling the function, I would need to use:
$data = $class->get_top_headlines( null, 'technology' );
Is there any way of calling the function more efficiently? I know I could pass the arguments as an array instead, but just wondered if there's any way of doing something like:
$data = $class->get_top_headlines( $category='technology' ); and automatically leaving the other arguments as their default of null?
public function get_top_headlines( $query=null, $category=null, $country=null, $sources=null, $page_size=null, $page=null ){
$url = $this->api_url . $this->endpoint_top_headlines;
$params = array();
if ( $query !== null ){
$params['q'] = urlencode( $query );
}
if ( $category !== null ){
$params['category'] = $category;
}
if ( $country !== null ){
$params['country'] = $country;
}
if ( $sources !== null ){
$params['sources'] = $sources;
}
if ( $page_size !== null ){
$params['pageSize'] = $page_size;
}
if ( $page !== null ){
$params['page'] = $page;
}
$params['apiKey'] = $this->api_key;
$url_query = http_build_query( $params );
$url = $url . '?' . $url_query;
echo $url;
$obj = $this->get_response( $url );
return $obj;
}
Try passing an array, and then using an array_merge
$data = $class->get_top_headlines(['category' => 'technology']);
Then in your function, have an array of defaults, then do your merge.
$settings = array_merge($settings, $passedInArray);
http://php.net/manual/en/function.array-merge.php
I think
(null, 'technology' );
might be less actual coding but a different solution might be to use OOP. You said it's already a method of a class so you could do something like:
$obj = new thatClass;
$obj->technology = $technology;
$obj->get_top_headlines();
in the Class:
Class thatClass{
$technology = null;
$category = null;
$query = null;
//...
public function get_top_headlines(){
if ( $this->query !== null ){
$params['q'] = urlencode( $this->query );
}
if ( $this->category !== null ){
$params['category'] = $this->category;
}
if ( $this->technology !== null ){
$params['technology'] = $this->technology;
}
//method code..
}
//class code..
}
The problem with this approach is if you need to call that same function again passing a different parameter in the same class instance, depending on your application you might need to manually set back to null the previous parameter (now an object attribute)
I would solve this problem by creating a new class or data structure which will encapsulate all the logic of validating and generating the URL and then use it everywhere I need it.
Here's a sample class.
class HeadLineParameters
{
private $params = [];
public function setQuery($query)
{
// validate/transform query data
$this->params['q'] = urlencode($query);
return $this;
}
public function setCategory($category)
{
// validate/transform category data
$this->params['category'] = $category;
return $this;
}
public function generateUrl()
{
return http_build_query( $this->params );
}
}
$params = new HeadLineParameters;
$params->setQuery($query)
->setCategory($category);
You just pass one argument and you know that it's just an instance of HeadLineParameters.
$class->get_top_headlines($params);
This solution doesn't pollute your current class with unnecessary state or fields. It is easy to test, and it has only one job. You can extend it easily, you can set default values, you can also validate it as you like.
Edit: Why you shouldn't add more fields to your current class?
If you add more fields to your current class you'll be breaking the single responsibility principle, and any method of this class can change these fields too. It shouldn't be a problem if these fields really belong there and more methods require them. This is fine if you are using OOP.
I am not sure what other people think about passing associated arrays to functions, but they are hard to handle if you have no documentation available. I have had trouble with them when reading some external code, and most of time I wasn't sure what's the data I was dealing with.
I have several interchangeable functions with different numbers of arguments, for example:
function doSomething1($arg1) {
…
}
function doSomething2($arg1, $arg2) {
…
}
I would like to pass a certain number of these functions, complete with arguments, to another handling function, such as:
function doTwoThings($thing1, $thing2) {
$thing1();
$thing2();
}
Obviously this syntax is not correct but I think it gets my point across. The handling function would be called something like this:
doTwoThings(‘doSomething1(‘abc’)’, ‘doSomething2(‘abc’, ‘123’));
So the question is, how is this actually done?
From my research it sounds like I may be able to "wrap" the "doSomething" function calls in an anonymous function, complete with arguments and pass those "wrapped" functions to the "doTwoThings" function, and since the anonymous function doesn't technically have arguments they could be called in the fashion shown above in the second code snippet. The PHP documentation has me confused and none of the examples I'm finding put everything together. Any help would be greatly appreciated!
you could make use of call_user_func_array() which takes a callback (eg a function or class method to run) and the arguments as an array.
http://php.net/manual/en/function.call-user-func-array.php
The func_get_args() means you can feed this funciton and arbitary number of arguments.
http://php.net/manual/en/function.func-get-args.php
domanythings(
array( 'thingonename', array('thing','one','arguments') ),
array( 'thingtwoname', array('thing','two','arguments') )
);
funciton domanythings()
{
$results = array();
foreach( func_get_args() as $thing )
{
// $thing[0] = 'thingonename';
// $thing[1] = array('thing','one','arguments')
if( is_array( $thing ) === true and isset( $thing[0] ) and is_callable( $thing[0] ) )
{
if( isset( $thing[1] ) and is_array( $thing[1] ) )
{
$results[] = call_user_func_array( $thing[0], $thing[1] );
}
else
{
$results[] = call_user_func( $thing[0] );
}
}
else
{
throw new Exception( 'Invalid thing' );
}
}
return $results;
}
This would be the same as doing
thingonename('thing','one','arguments');
thingtwoname('thing','two','arguments');
I'm trying to do the following in my controller:
public function moveMessagesToArchive( $message_ids = Input::get('message_ids') )
{
$json = json_encode( $message_ids);
echo $json;
}
And it keeps throwing the following error:
syntax error, unexpected '(', expecting ')'
at the function signature. What's causing the problem here?
Update
While, I wait for the reason I've written the following work around:
public function moveMessagesToArchive( $message_ids = array() )
{
$ids = array();
if ( ( count($message_ids) !== 0 ) && is_array($message_ids) ) {
$ids = $message_ids;
} else if ( Input::get('message_ids') ) {
$ids = Input::get('message_ids');
} else {
return false;
}
$json = json_encode( $ids );
echo $json;
}
It is not possible in PHP. According to the documentation
The default value must be a constant expression, not (for example) a variable, a class member or a function call.
Reference Example 4
What you are trying to do is not, and never has been supported by php.
Nothing at all to do with Laravel.
I'm setting up a PHP API that will expose functionality and vend data to my users, and I'm looking for an elegant way of passing to my functions the arguments that my users are "passing" to me. I can determine what method my users are calling ($_POST['method']) and depending on the method, zero or more arguments to the method. I validate them using a metadata array. For example:
$methods = array(
'say_hello' => array('name'),
'say_goodbye' => array(),
'do_something' => array( 'foo', 'bar' )
);
I have corresponding functions for these:
function say_hello( $name ) { printf( "Hello, %s, $name ); }
function say_goodbye() { printf( "Goodbye!" ); }
function do_something( $foo, $bar ) { printf( "%d + %d = %d.", $foo, $bar, $foo+$bar ); }
When a POST comes in, I check that the method they're requesting is an array key of mine (so they're not passing in $_POST['method'] = 'exec' or anything nefarious), and I can do the actual call as:
$method = $_POST['method'];
$method(); // make the call
And knowing the method also allows me to determine what - if any - arguments should go into it:
$args = $methods[ $method ]; // an array of 0-2 items
But is there a good way for me to combine this without a big if-elseif-elseif-... ?
if( 'say_hello'==$method )
$method( $_POST['name'] );
elseif( ... )
...
Something like Python's myfunc(*args) is what I'm looking to do, that would let me somehow accomplish:
$method = $_POST['method'];
$args = $methods[ $method ];
$method( $args );
Right now, my best bet is to load the arguments in the methods:
function do_something()
{
$foo = $_POST['foo'];
$bar = $_POST['bar'];
...
I am sorry, that sounds like a noob question. I am trying to do this, maybe my question is not clear.
I want to be able to pass something like this:
make_thumbnail( array( 'width' => 60, 'height' => 40', 'title' => 'my image' ) );
Now the above line calls the function which already produces the thumbnails I have that no problem, but I want flexibility here. I mean my function has variables ordered like this:
function make_thumbnail($title,$width,$height) {
the code..
echo ...
}
Now you get what I want to do? I want to be able to pass the variables in any order.. they do not have to come in same order title, width, height.. i want to be able to specify the order when I call the function in template as I put in very first line.
I tried to make my question as clear as I can, but really could not find anything about it.
This sort of thing?
function make_thumbnail($myarray) {
$sometitle = $myarray["title"]
$somewidth = $myarray["width"]
$someheight = $myarray["height"]
}
Why not have the array as the function argument? e.g.
function make_thumbnail($argsArray) {
echo $argsArray['width'];
}
You can create variables within your function for each parameter
function make_thumbnail($argsArray) {
$width = $argsArray['width'];
$height = $argsArray['height'];
$title = $argsArray['title'];
// ...plug the rest of your original function here
}
Then your function will behave exactly the same, except you can pass in an array.
What you're asking for is a description of the Reflection syntax of PHP:
function callWithNamedParams( $funcName, array $args = null )
{
if( is_null( $args ) ) return $funcName();
$f = new ReflectionFunction($funcName);
$input = array();
foreach( $f->getParameters() as $param )
{
array_push( $input, #$args[ $param->getName() ] );
}
return call_user_func_array( $funcName, $input );
}
Use:
function myFunc( $foo, $bar )
{
echo "foo = $foo; Bar = $bar";
}
callWithNamedParams( "myFunc", array( "bar"=>1, "foo"=>2 ) );
You should get foo = 2; Bar = 1 as an output.
you need to define your logic to take any parameter as the one you want it to be. Array is the best thing you can use. But changing the parameters changes the signatures.
you are kinda implementing polymorphism but in a wrong way..