Referans: Değişken kapsamı nedir, hangi değişkenlere nereden erişilebilir ve “tanımlanmamış değişken” hataları nelerdir?


167

Not: Bu, PHP'deki değişken kapsamla ilgilenmek için referans bir sorudur. Lütfen bu kalıba uyan birçok sorudan herhangi birini bu sorunun kopyası olarak kapatın.

PHP'de "değişken kapsam" nedir? Bir .php dosyasındaki değişkenlere başka bir dosyada erişilebilir mi? Neden bazen "tanımsız değişken" hataları alıyorum ?


1
Bunu "Tanımsız değişken" olarak adlandırdıysanız, daha fazla isabet alırsınız :) İyi iş olsa da
Dale

@Dale, Aslında hayır. 2 yılda 2
bin izlenme

7
@Pacerier ... rastgele bir yorum bırakmak için doğru zaman hakkında?
Dale

@Pacerier Bu yorumla ne söylemeye çalıştığınızdan gerçekten emin değilim. “Öyle ....” ... ne ?! : P
deceze

@Dale, Şimdi doğru zaman: Vay be GoogleDex'e " vatansız " kelimesi eklendikten sonra 2 yıl boyunca durgun olmasına rağmen, isabet oranı sadece 6 ayda 3x-ed.
Pacerier

Yanıtlar:


188

"Değişken kapsam" nedir?

Değişkenlerin sınırlı bir "kapsamı" veya "erişilebilir oldukları yerler" vardır. Yazdığın Çünkü $foo = 'bar';bir kere bir yere uygulamanızda size başvurmak anlamına gelmez $foogelen her yerde uygulama içinde başka. Değişkenin $foogeçerli olduğu belirli bir kapsamı vardır ve yalnızca aynı kapsamdaki kodun değişkene erişimi vardır.

PHP'de kapsam nasıl tanımlanır?

Çok basit: PHP fonksiyon kapsamına sahiptir . PHP'de var olan tek kapsam ayırıcısı budur. Bir işlevin içindeki değişkenler yalnızca bu işlevin içinde kullanılabilir. İşlevlerin dışındaki değişkenler işlevlerin dışında herhangi bir yerde bulunur, ancak hiçbir işlevin içinde kullanılamaz. Bu PHP'de özel bir kapsam olduğu anlamına gelir: global kapsam. Herhangi bir işlev dışında bildirilen herhangi bir değişken bu global kapsam dahilindedir.

Misal:

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;
}

$fooolduğu küresel , kapsam $bazbir olduğunu yerel kapsamı içine myFunc. Yalnızca içindeki kodun myFuncerişimi var $baz. Yalnızca dışarıdaki kodun myFuncerişimi var $foo. İkisinin de diğerine erişimi yok:

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;

    echo $foo;  // doesn't work
    echo $baz;  // works
}

echo $foo;  // works
echo $baz;  // doesn't work

Kapsam ve dahil edilen dosyalar

Dosya sınırları yapmak değil ayrı kapsamını:

a.php

<?php

$foo = 'bar';

b.php

<?php

include 'a.php';

echo $foo;  // works!

includeDiğer kodlar için geçerli olan d kodu için aynı kurallar geçerlidir : yalnızca functionayrı kapsamı. Kapsam amacıyla, kopyalama ve yapıştırma kodu gibi dosyaları dahil etmeyi düşünebilirsiniz:

c.php

<?php

function myFunc() {
    include 'a.php';

    echo $foo;  // works
}

myFunc();

echo $foo;  // doesn't work!

Yukarıdaki örnekte, a.phpiçine dahil edilmiş, içindeki myFuncdeğişkenler a.phpsadece yerel fonksiyon kapsamına sahiptir. Onlar sırf görünür küresel kapsamda olmak a.phpille oldukları anlamına gelmez, aslında kod dahil olduğunu / idam hangi bağlam bağlıdır.

Fonksiyonlar ve sınıflar içindeki fonksiyonlar ne olacak?

Her yeni functiondeklarasyon yeni bir kapsam getiriyor, bu kadar basit.

(anonim) işlevler içindeki işlevler

function foo() {
    $foo = 'bar';

    $bar = function () {
        // no access to $foo
        $baz = 'baz';
    };

    // no access to $baz
}

sınıflar

$foo = 'foo';

class Bar {

    public function baz() {
        // no access to $foo
        $baz = 'baz';
    }

}

// no access to $baz

Kapsam ne işe yarar?

Kapsam belirleme sorunlarıyla uğraşmak sinir bozucu görünebilir, ancak karmaşık uygulamalar yazmak için sınırlı değişken kapsam gereklidir! Bildirdiğiniz her değişken, uygulamanızın başka her yerinden kullanılabilirse, neyin değiştiğini izlemek için gerçek bir yol olmadan tüm değişkenlerinize adım atacaksınız. Değişkenlerinize verebileceğiniz çok fazla mantıklı isim var, büyük olasılıkla " $name" değişkenini birden fazla yerde kullanmak istiyorsunuz . Uygulamanızda bu benzersiz değişken adına yalnızca bir kez sahip olabilirseniz, değişkenlerinizin benzersiz olduğundan ve yanlış değişkeni yanlış kod parçasından değiştirmediğinizden emin olmak için gerçekten karmaşık adlandırma şemalarına başvurmanız gerekir.

Gözlemek:

function foo() {
    echo $bar;
}

Kapsam yoksa, yukarıdaki işlev ne yapardı? Nereden $bargeliyor? Hangi devleti var? Başlatılmış mı? Her seferinde kontrol etmek zorunda mısın? Bu sürdürülemez. Bu da bizi ...

Kapsam sınırlarını aşma

Doğru yol: değişkenleri içeri ve dışarı aktarmak

function foo($bar) {
    echo $bar;
    return 42;
}

Değişken $bar, işlev bağımsız değişkeni olarak açıkça bu kapsama giriyor. Sadece bu fonksiyona bakıldığında, çalıştığı değerlerin nereden kaynaklandığı açıktır. Daha sonra açıkça bir değer döndürür . Arayan, işlevin hangi değişkenlerle çalışacağını ve dönüş değerlerinin nereden geldiğini bilme güvenine sahiptir:

$baz   = 'baz';
$blarg = foo($baz);

Değişkenlerin kapsamını anonim işlevlere genişletme

$foo = 'bar';

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

$baz();

Anonim işlev $foo, etrafındaki kapsamı açıkça içerir . Bunun global kapsamla aynı olmadığını unutmayın .

Yanlış yol: global

Daha önce de belirtildiği gibi, küresel kapsam biraz özeldir ve işlevler açıkça değişkenleri buradan alabilir:

$foo = 'bar';

function baz() {
    global $foo;
    echo $foo;
    $foo = 'baz';
}

Bu işlev genel değişkeni kullanır ve değiştirir $foo. Bunu yapma! (Gerçekten ne yaptığınızı gerçekten bilmiyorsanız ve o zaman bile: Yapmayın!)

Bu işlevin tüm arayanı şudur:

baz(); // outputs "bar"
unset($foo);
baz(); // no output, WTF?!
baz(); // outputs "baz", WTF?!?!!

Bu işlevin herhangi bir yan etkisi olduğuna dair hiçbir belirti yoktur , ancak vardır. Bazı işlevler bazı küresel durumları değiştirmeye ve gerektirmeye devam ettiğinden bu çok kolay bir karışıklık haline gelir . İşlevlerin vatansız olmasını , yalnızca girdilerine göre hareket etmesini ve tanımlanmış çıktıyı döndürmesini istiyorsunuz, ancak birçok kez çağırıyorsunuz.

Global kapsamı mümkün olduğunca herhangi bir şekilde kullanmaktan kaçınmalısınız; şüphesiz değişkenleri küresel kapsamdan yerel bir kapsama “çekmemelisiniz”.


Sadece yanlış yoluglobal söylediniz , lütfen bize ne zaman kullanmamız gerektiğini söyleyin global? Ve açıklayınız (biraz) nedir edilir static..?

@stack "Doğru" bir yol yoktur global. Her zaman yanlış. Geçiş fonksiyonu parametreleri doğrudur. statickılavuzda iyi açıklanmıştır ve kapsamla fazla bir ilgisi yoktur. Özetle, "kapsamlı küresel değişken" olarak düşünülebilir. Burada kullanımı biraz daha genişletiyorum kunststube.net/static .
deceze

Benim basit düşünce, bir php değişkeni küresel bir durumu hak edecek kadar önemli ise, bir veritabanında bir sütun hak ediyor. Belki aşırıya kaçmış, ama vasat programlama zekâma uyan kusursuz bir yaklaşım
Arthur Tarasov

@Arthur Orada açılacak çok şey var… ಠ_ಠ Bu kesinlikle onaylayacağım bir yaklaşım değil.
deceze

@deceze wee bit burada bir tartışma biraz bitiyor stackoverflow.com/q/51409392 - burada OP yinelemenin (burada) bahsetmediğinden include_onceve muhtemelen bir require_onceyere eklenmesi gerektiğinden bahsediyor ; sadece söylüyorum. OP de sorularını yeniden açma kararı aldı. Görevleri özel bir durum olur mu ve bu konuda ne yapılmalı?
Funk Forty Niner

10

Bir işlevin kapsamı içinde tanımlanan değişkenlere dışarıdan erişilemese de, bu işlev tamamlandıktan sonra değerlerini kullanamayacağınız anlamına gelmez. PHP, staticstatik yöntemleri ve özellikleri tanımlamak için nesne yönelimli PHP'de yaygın olarak kullanılan iyi bilinen bir anahtar kelimeye sahiptir, ancak staticstatik değişkenleri tanımlamak için işlevler içinde de kullanılabileceğini unutmayın .

'Statik değişken' nedir?

Statik değişken, program yürütme bu kapsamdan çıktığında değer kaybetmemesi durumunda fonksiyonun kapsamında tanımlanan normal değişkenten farklıdır. Aşağıdaki statik değişkenleri kullanma örneğini ele alalım:

function countSheep($num) {
 static $counter = 0;
 $counter += $num;
 echo "$counter sheep jumped over fence";
}

countSheep(1);
countSheep(2);
countSheep(3);

Sonuç:

1 sheep jumped over fence
3 sheep jumped over fence
6 sheep jumped over fence

O $counterolmadan tanımlamış olsaydık, staticher seferinde yankı değeri $numişleve iletilen parametre ile aynı olurdu . Kullanma özelliği static, bu basit sayacı ek bir çözüm olmadan oluşturmanıza olanak tanır.

Statik değişkenler kullanım senaryoları

  1. Sonraki işlev çağrıları arasında değerleri saklamak için.
  2. Değerleri param olarak iletmenin bir yolu (veya amacı yok) olduğunda, yinelemeli çağrılar arasında değerleri saklamak için.
  3. Önbellek için normalde bir kez almak daha iyidir. Örneğin, sunucudaki sabit dosyayı okuma sonucu.

Hileler

Statik değişken yalnızca yerel işlev kapsamında bulunur. Tanımlandığı işlevin dışında erişilemez. Bu nedenle, bir sonraki işlev çağrısına kadar değerinin değişmeden kalacağından emin olabilirsiniz.

Statik değişken yalnızca skaler veya skaler ifade olarak tanımlanabilir (PHP 5.6'dan beri). Buna başka değerler atamak, en azından bu makalenin yazıldığı anda başarısızlığa neden olur. Yine de bunu sadece kodunuzun bir sonraki satırında yapabilirsiniz:

function countSheep($num) {
  static $counter = 0;
  $counter += sqrt($num);//imagine we need to take root of our sheep each time
  echo "$counter sheep jumped over fence";
}

Sonuç:

2 sheep jumped over fence
5 sheep jumped over fence
9 sheep jumped over fence

Statik işlev, aynı sınıftaki nesnelerin yöntemleri arasında 'paylaşılır'. Aşağıdaki örneği görüntüleyerek anlaşılması kolaydır:

class SomeClass {
  public function foo() {
    static $x = 0;
    echo ++$x;
  }
}

$object1 = new SomeClass;
$object2 = new SomeClass;

$object1->foo(); // 1
$object2->foo(); // 2 oops, $object2 uses the same static $x as $object1
$object1->foo(); // 3 now $object1 increments $x
$object2->foo(); // 4 and now his twin brother

Bu yalnızca aynı sınıftaki nesnelerle çalışır. Nesneler farklı sınıflardan geliyorsa (birbirini uzatan bile olsa) statik değişkenlerin davranışı beklendiği gibi olacaktır.

Statik değişken, bir işleve yapılan çağrılar arasında değerleri korumanın tek yolu mudur?

İşlev çağrıları arasında değerleri korumanın başka bir yolu da kapatmaları kullanmaktır. Kapanışlar PHP 5.3'te tanıtıldı. İki kelimeyle, bir işlev kapsamındaki bazı değişken kümelerine erişimi, bunlara erişmenin tek yolu olan başka bir anonim işleve sınırlamanızı sağlar. Kapatma değişkenlerinde olmak, yapılandırılmış programlamada 'sınıf sabitleri' (değere göre kapanışta geçildiyse) veya 'özel özellikler' (referansta geçildiyse) gibi OOP kavramlarını taklit edebilir (az çok başarılı bir şekilde).

İkincisi, statik değişkenler yerine kapakların kullanılmasına izin verir. Ne kullanmak her zaman karar vermek geliştiriciye bağlıdır, ancak statik değişkenlerin özyineleme ile çalışırken kesinlikle yararlı olduğu ve devs tarafından fark edilmeyi hak ettiği belirtilmelidir.


2

Mevcut olanlar ve PHP kılavuzu bunların çoğunu açıklamak için harika bir iş çıkardığı için soruya tam bir cevap göndermeyeceğim .

Ama kaçırılan bir konu olduğunu oldu Süper küreseller dahil, yaygın olarak kullanılan $_POST, $_GET, $_SESSIONvb Bu değişkenler bir olmadan, herhangi bir kapsamda, her zaman mevcuttur dizilerdir globalbeyanı.

Örneğin, bu işlev PHP komut dosyasını çalıştıran kullanıcının adını yazdırır. Değişken işlev için sorunsuz olarak kullanılabilir.

<?php
function test() {
    echo $_ENV["user"];
}

"Globaller kötü" genel kuralı genellikle PHP'de "globaller kötü ama süper küreseller iyi" olarak değiştirilir, ancak biri onları yanlış kullanmadıkları sürece. (Tüm bu değişkenler yazılabilir, bu yüzden gerçekten korkunç olsaydınız bağımlılık enjeksiyonunu önlemek için kullanılabilirler.)

Bu değişkenlerin mevcut olduğu garanti edilmez; Bir yönetici kullanarak bunlardan bazılarını veya tümünü devre dışı bırakabilir variables_orderdirektifini de php.iniancak bu ortak davranıştır değil.


Mevcut süper küresellerin bir listesi:

  • $GLOBALS - Geçerli komut dosyasındaki tüm global değişkenler
  • $_SERVER - Sunucu ve yürütme ortamı hakkında bilgi
  • $_GET - İstek için kullanılan HTTP yöntemine bakılmaksızın URL'nin sorgu dizesinde iletilen değerler
  • $_POST- Değerler bir HTTP POST isteğinde application/x-www-form-urlencodedveya multipart/form-dataMIME türlerinde iletildi
  • $_FILES- multipart/form-dataMIME türünde bir HTTP POST isteğinde iletilen dosyalar
  • $_COOKIE - Geçerli istekle iletilen çerezler
  • $_SESSION - PHP tarafından dahili olarak depolanan oturum değişkenleri
  • $_REQUEST- Tipik olarak $_GETve $_POST, ancak bazen bir kombinasyonudur $_COOKIES. İçerik tarafından belirlenir request_orderyönergede yer php.ini.
  • $_ENV - Geçerli komut dosyasının ortam değişkenleri
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.