0

I have the following code.

function up() {
    $runafterupdate = [];
    Schema::connection('exitproducts')->create('exitcontrol_carmanager_manager',  function($table)
                {
                    $table->engine = 'InnoDB';
                    $table->increments('id');
                    $table->string('code');
                    $runafterupdate['code'] = true;
                    $table->timestamps();
                });
            }
    if(isset($runafterupdate['code'])) {
        echo "it worked!";
    }
}

And i'm used to JavaScript where you can alter the values of the parent scope, but aparently php follows different rules. I've tried reading through http://php.net/manual/en/language.variables.scope.php but I really don't want to use globals.

Is there a way to alter the variables in the parent scope with php or is my only resort in this case a global variable?

Tschallacka
  • 27,901
  • 14
  • 88
  • 133

4 Answers4

2

2021 update courtesy of George

It's no longer necessary. For searchers in the future: If you use the new (PHP>=7.4) "arrow function" notation for anonymous functions, variables in the parent are automatically accessible to you by-value. No use tag needed. php.net/manual/en/functions.arrow.php


After some more digging... why do I always find the answers AFTER I post a question...

Using the use clause on the function you can use the variables you declare there in the "child" scope. That this isnt highlighted in the scope documentation in php docs beats me.

Extracted from Reference: What is variable scope, which variables are accessible from where and what are "undefined variable" errors?

Extending the scope of variables into anonymous functions

$foo = 'bar';

$baz = function () use ($foo) {
    echo $foo;
};

$baz();

After some fiddling I found i can't directly modify array variables. Any modifications stay in the function scope but dont lift over to the parent scope.

I made a simple holder object with setters and getters to get it to work.

function scop1() {
/** simple class to hold vars **/
class holder {
 public $held = [];
 /** setter **/
 function update($what, $with) {
        $this->held[$what] = $with;
    }
 /** getter **/
 function get($what) {
    if(isset($this->held[$what])) return $this->held[$what];
    else return null;
 }
}
$var = new holder();
/** works **/
$var->update('hello','bye');
$x = function() use ($var) {
   /** modify parent scope **/
   $var->update('hello','hello');
};
/** call anomynous function **/
$x();
/** it should say hello hello in held **/
var_dump($var);
}
scop1();

live sample: http://sandbox.onlinephpfunctions.com/code/d7464356c0712f2606b0f70ab952be4d782374dc

Tschallacka
  • 27,901
  • 14
  • 88
  • 133
  • `can't directly modify array variables` : how about `function() use (&$ref) {...}` - that should modify the passed var, since its passed as a reference – birdspider Jul 03 '15 at 08:39
  • oh wow... that actually works :-) Thank you. you made my life with php scopes a lot easier :-) Make an answer explaning stuff and i'll accept it. – Tschallacka Jul 03 '15 at 09:00
  • beware though, IIRC its quite impossible to get rid of a reference in php `&array(..)` once it's in place, (if i.e. later you want a copy which is not a reference) – birdspider Jul 03 '15 at 09:03
  • nah, its only shortlived to set a flag. I unset the whole shebang when the settings runs are over. – Tschallacka Jul 03 '15 at 09:22
  • 2021 update: this Q/A came up for me in a search and worked, but later I found out it's no longer necessary. So, for searchers in the future: If you use the new (PHP>=7.4) "arrow function" notation for anonymous functions, variables in the parent are automatically accessible to you by-value. No `use` tag needed. https://www.php.net/manual/en/functions.arrow.php – George Oct 13 '21 at 19:30
  • @George I wonder how this slipped by me. I wished I had known this earlier! Thanks, I'll incorperate it in the answer. – Tschallacka Oct 14 '21 at 16:21
1

If this function is inside a class, I don't see a problem if you declare your variable as public, private or protected ( I would go with private and create set/get functions for this variable if necessary). After that you can do $this->runafterupdate = true inside your anonymous function. If your function is not inside a class I would go with globals, but I really don't suggest that.

Hove you tried with the use keyword`?

Stanimir Dimitrov
  • 1,872
  • 2
  • 20
  • 25
0

You have an anonymous function, declare $runafterupdate as a private array in your class and in the anonymous function use $this->runafterupdate then check it. I`m guessing you are using Laravel

class Demo
{
    private $runafterupdate;
    ...
    public function up() {
        Schema::connection('exitproducts')->create('exitcontrol_carmanager_manager',  function($table)
                    {
                        $table->engine = 'InnoDB';
                        $table->increments('id');
                        $table->string('code');
                        $this->runafterupdate['code'] = true;
                        $table->timestamps();
                    });
                }
        if(isset($this->runafterupdate['code'])) {
            echo "it worked!";
        }
    }
    ...
}

This should work, if I`m not mistaken I had a similar issue

ka_lin
  • 9,329
  • 6
  • 35
  • 56
  • uhm.. you have an anomynous function that gets passed to the schema create, not a class isntance. I'd have to make a class function and pass that. That isn't how it works. I posted an answer with the correct desired behaviour making proper use of scoping methods. I find it actually better than the javascript way where everything is just passed on to child scopes. – Tschallacka Jul 03 '15 at 07:57
0

Using a Closure with & will do the trick.

function test()
{
  $var = 20;

  $anonymous = function () use (&$var) {
    $var++;
  };

  $anonymous();

  echo $var; // 21
}

If you just want to pass just the value, use closure without &

$anonymous = function () use ($var) { ... }
Utsav Barnwal
  • 985
  • 11
  • 14