Forum und email

טווח ההכרה של משתנים

טווח ההכרה של המשתנים הוא ההקשר בו הם מוגדרים. על פי רוב לכל משתני הPHP ישנו טווח הכרה יחיד. טווח ההכרה יכול לכלול (ע"י include או require) ללא כל בעיה לדוגמא:

<?php
$a 
1;
include 
"b.inc";
?>

כאן, המשתנה $a יהיה זמין בתוך הקובץ b.inc שכללנו. לעומת זאת, בתוך פונקציות של המשתמש, טווח הגדרה שונה מוכנס לשימוש. כל המשתנים שמשמשים בתוך הפונקציה מוגבלים כברירת מחדל לטווח המקומי של הפונקציה. לדוגמא:

<?php
$a 
1/* global scope */

function Test()
{
    echo 
$a/* reference to local scope variable */
}

Test();
?>

הסקריפט הזה לא ייצר פלט מכיוון שההצהרה echo מתייחסת לגירסא המקומית של המשתנה $a, שלא הוקצה לו ערך בטווח ההכרה המקומי של הפונקציה. אולי שמת לב שקיים פה שוני משפת C, שם המשתנים הגלובליים אוטומטית זמינים לפונקציות, אלא אם כן הם נרמסו על ידי משתנים מקומיים. בPHP משתנים גלובליים חייבים להיות מוגדרים בתוך הפונקציה אם רוצים להשתמש בהם.

ההנחיה global

נפתח בדוגמא לשימוש בglobal:

Example#1 השימוש ב global

<?php
$a 
1;
$b 2;

function 
Sum()
{
    global 
$a$b;

    
$b $a $b;
}

Sum();
echo 
$b;
?>

הפלט של הסקריפט שלעיל יהיה "3". על ידי ההצהרה על $a ו $b כ global בתוך פונקציה, כל איזכור של משתנים אלו יכוון לגרסתם הגלובאלית. אין כל מגבלה על מספר המשתנים הגלובאליים עליהם ניתן להצהיר בתוך פונקציה.

דרך נוספת לגשת לאותם משתנים בטווח ההגדרה הראשי של הPHP היא באמצעות המערך המיוחד $GLOBALS. הדוגמא הקודמת יכולה להשתכתב כ:

Example#2 שימוש ב $GLOBALS במקום global

<?php
$a 
1;
$b 2;

function 
Sum()
{
    
$GLOBALS["b"] = $GLOBALS["a"] + $GLOBALS["b"];
}

Sum();
echo 
$b;
?>

המערך $GLOBALS הוא מערך אסוטיאטיבי בו השם של המשתנה הגלובאלי נהיה המפתח לאיבר במערך המכיל את תוכן המשתנה הגלובאלי. שים לב ש$GLOBALS קיים בכל טווח הכרה מפני ש $GLOBALS הוא סופר גלובאלי. הנה כמה דוגמאות הממחישות את הכח של סופר גלובאליים:

Example#3 דוגמאות הממחישות את השימוש בסופר גלובאליים וטווח ההכרה

<?php
function test_global()
{
    
// Most predefined variables aren't "super" and require
    // 'global' to be available to the functions local scope.
    
global $HTTP_POST_VARS;

    print 
$HTTP_POST_VARS['name'];

    
// Superglobals are available in any scope and do
    // not require 'global'.  Superglobals are available
    // as of PHP 4.1.0
    
print $_POST['name'];
}
?>

שימוש במשתנים סטאטיים

אפשרות חשובה נוספת הקשורה לטווח ההגדרה של משתנים היא השימוש במשתנה סטאטי. משתנה סטאטי קיים אך ורק בטווח ההגדרה של פונקציה מקומית, אך הוא איננו מאבד את ערכו כאשר התוכנית עוזבת את הפונקציה. שים לב לדוגמא הבאה:

Example#4 דוגמא הממחישה את הצורך במשתנים סטאטיים

<?php
function Test ()
{
    
$a 0;
    echo 
$a;
    
$a++;
}
?>

הפונקציה הזו די לא שימושית מכיוון שכל פעם שקוראים לה היא מאתחלת מחדש את $a ל 0 ומדפיסה "0". ההנחיה $a++ שמגדילה את ערך המשתנה לא משפיעה על כלום מכיוון שביציאה מהפונקציה המשתנה $a בלאו הכי נעלם. על מנת להשמיש את הפונקציה אנחנו צריכים שהפונקציה לא תאבד את ערך המשתנה, ועל כן אנו מגדירים את המשתנה $a כסטאטי:

Example#5 דוגמא לשימוש במשתנים סטאטיים

<?php
function Test()
{
    static 
$a 0;
    echo 
$a;
    
$a++;
}
?>

עכשיו, עבור כל קריאה לפונקציה Test() הערך $a יודפס ויקודם.

משתנים סטאטיים מספקים דרך מעניינת ליישם פונקציות רקורסיביות. פונקציה רקורסיבית היא פונקציה שקוראת לעצמה. בכתיבת פונקציות רקורסיביות יש להזהר שלא לחזור על התהליך לנצח, אתה חייב להיות בטוח שיש לך דרך לעצור את הרקורסיה. הפונקציה הרקורסיבית הבאה מונה עד 10 ומשתמשת במשתנה הסטאטי $count על מנת לדעת היכן לעצור:

Example#6 משתנים סטאטיים ופונקציות רקורסיביות

<?php
function Test()
{
    static 
$count 0;

    
$count++;
    echo 
$count;
    if (
$count 10) {
        
Test ();
    }
    
$count--;
}
?>

מכוונים ומשתנים גלובאליים וסטאטיים

עבור המנוע ZEND בגירסא 1, המהווה תשתית לPHP4, ישום של static ו global נעשה בעזרת מכוונים. לדוגמא, משתנה גלובאלי המיובא לטווח ההכרה של פונקציה בעזרה המשפט global למעשה יוצר מכוון למשתנה הגלובאלי. התנהגות זו יכלה להוליד התנהגות לא צפויה כפי שמדגימה הדוגמא הבאה:

<?php
function test_global_ref() {
    global 
$obj;
    
$obj = &new stdclass;
}

function 
test_global_noref() {
    global 
$obj;
    
$obj = new stdclass;
}

test_global_ref();
var_dump($obj);
test_global_noref();
var_dump($obj);
?>

הרצת הדוגמא מייצרת את הפלט הבא:

NULL
object(stdClass)(0) {
}
   

התנהגות דומה קורת בשימוש במשפט static. מכוונים לא נשמרים סטאטית:

<?php
function &get_instance_ref() {
    static 
$obj;

    echo 
"Static object: ";
    
var_dump($obj);
    if (!isset(
$obj)) {
        
// Assign a reference to the static variable
        
$obj = &new stdclass;
    }
    
$obj->property++;
    return 
$obj;
}

function &
get_instance_noref() {
    static 
$obj;

    echo 
"Static object: ";
    
var_dump($obj);
    if (!isset(
$obj)) {
        
// Assign the object to the static variable
        
$obj = new stdclass;
    }
    
$obj->property++;
    return 
$obj;
}

$obj1 get_instance_ref();
$still_obj1 get_instance_ref();
echo 
"\n";
$obj2 get_instance_noref();
$still_obj2 get_instance_noref();
?>

פלט הדוגמא יראה כך:

Static object: NULL
Static object: NULL

Static object: NULL
Static object: object(stdClass)(1) {
  ["property"]=>
  int(1)
}
   

הדוגמא מדגימה שכאשר מקצים מכוון למשתנה סטאטי, הוא לא נשמר כאשר אתה קורא לפונקציה &get_instance_ref() בפעם השניה.