94
function parts($part) { 
    $structure = 'http://' . $site_url . 'content/'; 
    echo($tructure . $part . '.php'); 
}

This function uses a variable $site_url that was defined at the top of this page, but this variable is not being passed into the function.

How do we get it to return in the function?

stakx - no longer contributing
  • 83,039
  • 20
  • 168
  • 268
Walrus
  • 19,801
  • 35
  • 121
  • 199

7 Answers7

177

Add second parameter

You need to pass additional parameter to your function:

function parts($site_url, $part) { 
    $structure = 'http://' . $site_url . 'content/'; 
    echo $structure . $part . '.php'; 
}

In case of closures

If you'd rather use closures then you can import variable to the current scope (the use keyword):

$parts = function($part) use ($site_url) { 
    $structure = 'http://' . $site_url . 'content/'; 
    echo $structure . $part . '.php'; 
};

global - a bad practice

This post is frequently read, so something needs to be clarified about global. Using it is considered a bad practice (refer to this and this).

For the completeness sake here is the solution using global:

function parts($part) { 
    global $site_url;
    $structure = 'http://' . $site_url . 'content/'; 
    echo($structure . $part . '.php'); 
}

It works because you have to tell interpreter that you want to use a global variable, now it thinks it's a local variable (within your function).

Suggested reading:

Anthony Hatzopoulos
  • 10,437
  • 2
  • 40
  • 57
Zbigniew
  • 27,184
  • 6
  • 59
  • 66
  • The adding a second or more parameter is not always the most practical thing. It simply increases the number of arguments we have to pass every time we are calling a function, in my case where I am building a function that works on strings and is repeated multiple times throughout the page it is very difficult to make it this way, – Deepak Kamat Nov 13 '19 at 19:02
  • 1
    Also adding a second parameter may not always be possible, for example with array_filter() or similar cases where you cannot influence the caller. – BlaM Nov 13 '20 at 13:05
  • 1
    The 'use' keyword is great to know about! Thank you. As the other commenters mentioned, the callable signature can't always be changed like in the case of array_map. But 'use' allows out-of-scope variables to be brought into the lambda function for use during the loop. – phip Aug 25 '22 at 03:57
49

Alternatively, you can bring variables in from the outside scope by using closures with the use keyword.

$myVar = "foo";
$myFunction = function($arg1, $arg2) use ($myVar)
{
 return $arg1 . $myVar . $arg2;
};
Joe Green
  • 1,745
  • 1
  • 12
  • 17
  • 2
    This way is a little hard, for example if you have 10 variable this way will be hard. – Mohammad Kermani May 10 '14 at 08:09
  • 1
    php shows error, why? Parse error: syntax error, unexpected 'use' (T_USE), expecting '{' – Mohammad Kermani May 10 '14 at 08:12
  • 1
    @Kermani you are probably using an older version of PHP which does not have the `use` syntax. This syntax was introduced in PHP5.3. See https://wiki.php.net/rfc/closures – Joe Green Sep 11 '14 at 13:52
  • @JoeGreen, what is this functionality known as to be able to use the variables that are defined outside of function. – Gunnrryy Aug 01 '17 at 10:03
  • @Gunnrryy look up closures and scope – Joe Green Aug 01 '17 at 16:30
  • 2
    @thiout_p I think it's too late to answer. but maybe somebody else is seeking the answer: closures are defined in variables and has no names $myFunction = function myFunction() this is a wrong syntax. and using lexical variables is not possible. the right syntax is **$myFunction = function()** then lexical variables would be allowed. to call the closure $myFunction() – pixxet Nov 27 '18 at 06:41
13

Do not forget that you also can pass these use variables by reference.

The use cases are when you need to change the use'd variable from inside of your callback (e.g. produce the new array of different objects from some source array of objects).

$sourcearray = [ (object) ['a' => 1], (object) ['a' => 2]];
$newarray = [];
array_walk($sourcearray, function ($item) use (&$newarray) {
    $newarray[] = (object) ['times2' => $item->a * 2];
});
var_dump($newarray);

Now $newarray will comprise (pseudocode here for brevity) [{times2:2},{times2:4}].

On the contrary, using $newarray with no & modifier would make outer $newarray variable be read-only accessible from within the closure scope. But $newarray within closure scope would be a completelly different newly created variable living only within the closure scope.

Despite both variables' names are the same these would be two different variables. The outer $newarray variable would comprise [] in this case after the code has finishes.

NB: Do not forget that you would better use the immutable data structures (unlike the above) in your common web project. That would account for 99% of the use cases. So the approach above, using mutabliity, is for very seldom kind of "low level" use cases.

Valentine Shi
  • 6,604
  • 4
  • 46
  • 46
  • 1
    This method fixed my (different) problem where updating the variable being used from the outer scope wouldn't be reflected within the function. Referring to it by reference would allow me to get the value at that point in time from the outer scope. – Alex W May 09 '19 at 23:44
2

I suppose this depends on your architecture and whatever else you may need to consider, but you could also take the object-oriented approach and use a class.

class ClassName {

    private $site_url;

    function __construct( $url ) {
        $this->site_url = $url;
    }

    public function parts( string $part ) {
        echo 'http://' . $this->site_url . 'content/' . $part . '.php';
    }

    # You could build a bunch of other things here
    # too and still have access to $this->site_url.
}

Then you can create and use the object wherever you'd like.

$obj = new ClassName($site_url);
$obj->parts('part_argument');

This could be overkill for what OP was specifically trying to achieve, but it's at least an option I wanted to put on the table for newcomers since nobody mentioned it yet.

The advantage here is scalability and containment. For example, if you find yourself needing to pass the same variables as references to multiple functions for the sake of a common task, that could be an indicator that a class is in order.

Leon Williams
  • 674
  • 1
  • 7
  • 15
0

I had similar question. Answer: use global. And there are other options. But if you need named function with usage of outside scope, here what I have:

global $myNamedFunctionWidelyAccessibleCallableWithScope;
$myNamedFunctionWidelyAccessibleCallableWithScope =
    function ($argument) use ($part, $orWhatYouWant) {
        echo($argument . $part . '.php');
        // do something here
        return $orWhatYouWant;
    };
function myNamedFunctionWidelyAccessible(string $argument)
{
    global $myNamedFunctionWidelyAccessibleCallableWithScope;
    return $myNamedFunctionWidelyAccessibleCallableWithScope($argument);
}

It is useful for making function myNamedFunctionWidelyAccessible accissible from everywhere, but also binds it with scope. And I deliberately gave very long name, global things are evil :(

Here is documentation with a good example

Grigory
  • 411
  • 3
  • 10
0

You can add the below structure

$var1=5;
function sample() use ($var1){echo $var1;}
Kapil Kumar
  • 143
  • 3
-1

Just put in the function using GLOBAL keyword:

 global $site_url;
TarangP
  • 2,711
  • 5
  • 20
  • 41
HBv6
  • 3,487
  • 4
  • 30
  • 43