skip to Main Content

I have the code below that in the case of function ‘test’ works as required, while when the work of ‘foreach’ is factored into a function things stop working as variables go out of scope. Is there a way to maintain them in scope while being able to factor the code as a function?

function test()
{
    $a = 'aaa';
    $b = 'bbb';
    $c = 'ccc';
    $A = ['a', 'b', 'c'];
    foreach ($A as $_a) $r[$_a] = $$_a;
    var_dump($r);
}

// running test() gives ['a'=>'aaa','b'=>'bbb','c'=>'ccc']

function KV($A)
{
    foreach ($A as $_a) $r[$_a] = $$_a;
    return $r;
}

function test1()
{
    $a = 'aaa';
    $b = 'bbb';
    $c = 'ccc';
    $A = ['a', 'b', 'c'];
    $r = KV($A);
    var_dump($r);
}

running test1() gives ['a'=>NULL,'b'=>NULL,'c'=>NULL]
comment: the looping variable has been named ‘_a’ in order to avoid name clashes with possible variable names.

just to understand the usefulness of the need, I write bellow a real case where the function would be used.

$r = [
    'series' => $series, 
    'aa' => $aa, 
    'issueDate' => $issueDate, 
    'invoiceType' => $invoiceType, 
    'vatPaymentSuspension' => $vatPaymentSuspension, 
    'currency' => $currency, 
    'exchangeRate' => $exchangeRate,
    ];
if ($correlatedInvoices) {
    $r['correlatedInvoices'] = $correlatedInvoices;
}
if ($selfPricing) {
    $r['selfPricing'] = $selfPricing;
}

3

Answers


  1. Chosen as BEST ANSWER

    It seems that actually there is no way to do it,so I present the solution I devised to do the same bypassing the lack of options. By the way I suggest to the language designer to provide a bidimensional array like $LOCALS where we can access values of previous calls as $LOCALS[-1]['nameOfLocalInCallingFunction'] or something similar ($LOCALS[1])

    The solution bellow seems the best option available to obtain the scope at hand:

    <?php
    
    function test(){
      $a='aaa';$b='bbb';$c='ccc';
      $A=['a','b','c'];
      foreach($A as $_a) $r[$_a]=$$_a;
      var_dump($r);
    }
    
    // running test() gives ['a'=>'aaa','b'=>'bbb','c'=>'ccc']
    
    function KV($A){
      foreach($A as $a) 
        $r[]="'$a'=>$$a";
      return '[' . implode(',',$r) . '];' ;
    }
    
    function test1(){
      $a='aaa';$b='bbb';$c='ccc';
      $A=['a','b','c'];
      eval('$r='.KV($A));
      var_dump($r);
    }
    
    // running test1() now gives ['a'=>'aaa','b'=>'bbb','c'=>'ccc']
    

  2. You can pass the array by reference to be able to update within the function’s scope.

    function KV(&$A, $t) {
        foreach ($A as $k => $v) {
            $A[$k] = $t[$v];
        }
    }
    
    function test1() {
        $t = [
            "a" => 'aaa',
            "b" => 'bbb',
            "c" => 'ccc',
        ];
    
        $A = ['a', 'b', 'c'];
        KV($A, $t);
        var_dump($A);
    }
    
    Login or Signup to reply.
  3. You can give all variables defined to your function with get_defined_vars() https://www.php.net/manual/en/function.get-defined-vars.php

    function KV($varsToGet,$varsDefined){
      $returnArray = [];
      foreach($varsToGet as $varToGet) 
        if(isset($varsDefined[$varToGet])){
          $returnArray[$varToGet] = $varsDefined[$varToGet];
        }
      return $returnArray;
    }
    
    function test1(){
      $a='aaa';
      $b='bbb';
      $c='ccc';
      $A=['a','b','c'];
      $r = KV($A,get_defined_vars());
      print_r($r);
    }
    

    or

    function test1(){
      $a='aaa';
      $b='bbb';
      $c='ccc';
      $A=['a','b','c'];
      $r = array_filter(get_defined_vars(),function($index)use($A){ 
        return in_array($index,$A);
      },ARRAY_FILTER_USE_KEY);
      print_r($r);
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search