2016-05-27 18 views
1

グローバル変数が悪であることはよく認識しており、これは後でで扱う問題です。私のコードベースではありませんが、私はいくつかのクリーンアップタスクを割り当てられています。クロージャ内のグローバルスコープからの変数へのアクセス

コードベースをスマートにしようとすると、私はAltoRouterというパッケージを使用して簡単なルーティングを実装することに決めました。以前はそれを使っていました。

ここで、コードベースはグローバルスコープで宣言された大量の変数を使用しています。通常、これらの変数はglobalキーワードを使用して取得されます。しかし何らかの理由で、私がクロージャの中で作業しているときにはこれは機能しません。

は、この単純なルーティングの例を考えてみましょう:

<?php 
require 'vendor/autoload.php'; 
$router = new AltoRouter(); 

$router->map('GET', '/shops/[i:id]', function($id) { 

    $_GET['shop_id'] = $id; 
    require 'go_to_shop.php'; 
}); 

$match = $router->match(); 

if($match && is_callable($match['target'])) { 
    call_user_func_array($match['target'], $match['params']); 
} 

これは、変数を設定し、ファイルを必要とし、私の閉鎖を呼び出します。

これはエラーを生成します。

Fatal error: Call to a member function get() on null in /vagrant/Core/CampaignHandler.php on line 71

は今、これを行うと呼ばれているコードは、以下の(ライン70-71)されています

// Inside a method 
global $serviceContainer; 
$dispatcher = $serviceContainer->get("dispatcher"); 

$serviceContainerは、ファイルを含むによって宣言されています早い段階で:

$serviceContainer = new ServiceContainer(); 
$serviceContainer->set("dispatcher", new EventDispatcher()); 

基本的に、クロージャーの内容をcすべてが完璧に機能しますが、閉鎖の内側から実行するとすぐに、グローバルスコープ経由でアクセスされるすべての変数は空になります。なぜか、私には分かりません。

閉鎖時にuseを使用しようとしましたが、これはどちらも機能しませんでした。

私はほとんど解決策ではなく説明を探しています。

+1

'$ serviceContainer'が宣言されているファイルは関数内に*含まれていますか? – deceze

+0

@deceze、いいえ、それはインクルードされたファイルであり、 '$ serviceContainer'はグローバル変数スコープにあります。 – Repox

答えて

1

なぜなら、グローバルは悪いことです。関数が呼び出された時点でグローバルが初期化されていないため、エラーが発生します。 globalrequireの混乱が問題であり、すでに対処しようとしています。

クロージャ自体でグローバルを使用することは問題ありません。この例では完全に正常に動作します:

global.php:

<?php 
class Foo { 
    public function bar() { return 'bar';} 
} 

$foo = new Foo; 

test.phpを:

<?php 
require 'global.php'; 

$test = function($param) { 
    global $foo; 
    echo $param, $foo->bar(); 
} 

call_user_func_array($test, ['baz']); 

のでphp test.php出力bazbar

+0

ありがとうございます。今私は仕事をすることがあります。 – Repox

0

$serviceContainer変数がグローバルスコープに存在しないことは間違いありませんが、問題はその部分を外しています。

use($serviceContainer)ステートメントを使用して、匿名関数にコンテナを渡すことはできませんか?そうすれば、グローバルに頼る必要がなくなります。オフトピック

function($id) use($serviceContainer) { 

    $_GET['shop_id'] = $id; 
    require 'go_to_shop.php'; 
} 

:あなたは後でそのid変数でやっていると、なぜあなたはそのようにバックの$ _GET変数にそれを入れますが、気をつけてくださいているのかわかりません。

-1

実際にオブジェクトであるクロージャーとも呼ばれるアノニマス関数のマニュアルを確認してください。

http://php.net/manual/en/functions.anonymous.php

論文呼び出し可能オブジェクトは、その範囲を拡張するための特定の機能を持っています。

参照:例3親スコープの変数を継承する

$message = 'hello'; 

// No "use" 
$example = function() { 
    var_dump($message); 
}; 
$example(); 

// Inherit $message 
$example = function() use ($message) { 
    var_dump($message); 
}; 
$example(); 

確かに、$ _GETグローバル変数に値を割り当てたいですか?

$_GET['shop_id'] = $id; 

あなたはaltorouterパラメータから抽出することができ、あなたのルートに店舗ID。 (ドキュメントを参照してください。)

$router->map('GET', '/', function() { .. }, 'home'); 

// assuming current request url = '/' 
$match = $router->match(); 

/* 
array(3) { 
    ["target"] => object(Closure)#2 (0) { } 
    ["params"] => array(0) { } 
    ["name"] => 'home' 
} 
*/ 

それとも、セッションを使用する$ _COOKIESまたは$ _SESSIONグローバル変数のIDを保存したい場合。