Forum und email

Εμβέλεια μεταβλητών

Η εμβέλεια των μεταβλητών καθορίζεται από το περιεχόμενο μέσα στο οποίο ορίζεται. Για την πλειοψηφία των μεταβλητών της PHP υπάρχει μόνο ενός είδους εμβέλεια. Αυτή η εμβέλεια περιέχει τόσο τα αρχεία που περιέχονται όσο και αυτά που απαιτούνται. Για παράδειγμα:

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

Εδώ η μεταβλητή $a θα είναι διαθέσιμη μέσα στο εμπεριεχόμενο b.inc script. Πάντως, μέσα σε συναρτήσεις που ορίζονται από το χρήστη εισάγεται εμβέλεια τοπικής συνάρτησης (local function scope). Οποιαδήποτε μεταβλητή χρησιμοιποιείται μέσα σε μια συνάρτηση είναι εκ των προτέρων περιορισμένη σε εμβέλεια τοπικής συνάρτησης. Για παράδειγμα:

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

function Test()

    echo 
$a/* reference to local scope variable */ 


Test();
?>

Αυτό το script δε θα δώσει κάποιο αποτέλεσμα επειδή η echo δήλωση αναφέρεται σε μια τοπική έκδοση της $a μεταβλητής, και δεν της έχει ανατεθεί μια τιμή μέσα σ'αυτή την εμβέλεια. Ίσως παρατηρείσετε ότι είναι λίγο διαφορετική από τη C γλώσσα από την άποψη ότι οι global μεταβλητές στη C είναι άμεσα διαθέσιμες σε συναρτήσεις εκτός και αν επικαλύπτονται αυτόματα από κάποια τοπική αναφορά. Αυτό μπορεί να προκαλέσει μερικά προβλήματα αν κάποιοι, ακούσια, αλλάξουν μια global μεταβλητή. Στην PHP οι global μεταβλητές πρέπει να οριστούν ως global μέσα στη συνάρτηση αν πρόκειται να χρησιμοποιηθούν σ'αυτή τη συνάρτηση. Ένα παράδειγμα :

The global keyword

Πρώτα, ένα παράδειγμα από τη χρήση της global:

Example#1 Χρησιμοποιώντας global

<?php
$a 
1;
$b 2;

function 
Sum()
{
    global 
$a$b;

    
$b $a $b;


Sum();
echo 
$b;
?>

Το παραπάνω script θα δώσει "3". Δηλώνοντας την $a και την $b ως global μέσα σε μια συνάρτηση, όλες οι αναφορές σε οποιαδήποτε από τις μεταβλητές θα αναφέρονται στην global έκδοση. Δεν υπάρχει περιορισμός στον αριθμό των global μεταβλητών που μπορεί να χειριστεί μια συνάρτηση.

Ένας δεύτερος τρόπος για να προσπελάσουμε μεταβλητές από global εμβέλεια είναι να χρησιμοποιήσουμε τον ειδικά ορισμένο από την PHP $GLOBALS array. Το προηγούμενο παράδειγμα μπορεί να ξαναγραφτεί ως:

Example#2 Χρησιμοποιώντας την $GLOBALS αντί για την global

<?php
$a 
1;
$b 2;

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


Sum();
echo 
$b;
?>

Ο πίνακας $GLOBALS είναι ένας associative array με το όνομα της global μεταβλητής να είναι το κλειδί και τα περιεχόμενα αυτής της μεταβλητής να είναι η τιμή του στοιχείου του array. Σημειώστε πώς η $GLOBALS υπάρχει σε κάθε εμβέλεια, κάτι το οποίο συμβαίνει επειδή η $GLOBALS είναι μια superglobal. Δείτε ένα παράδειγμα που δείχνει τη δύναμη των superglobals:

Example#3 Παράδειγμα που δείχνει τις superglobals και την εμβέλεια

<?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'];
}
?>

Χρησιμοποιώντας στατικές μεταβλητές

Ένα επιπλέον σημαντικό χαρακτηριστικό της εμβέλειας μεταβλητών είναι η static μεταβλητή. Μια στατική μεταβλητή υπάρχει μόνο σε εμβέλεια τοπικής συνάρτησης, αλλά δεν χάνει την τιμή της όταν η εκτέλεση του προγράμματος αφήνει αυτή την εμβέλεια. Θεωρείστε το ακόλουθο παράδειγμα:

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--;
}
?>

Αναφορές με στατικές και global μεταβλητές

Η Zend Engine 1, που οδηγεί την PHP4, υλοποιεί τον στατικό και global modifier για τις μεταβλητές όσον αφορά τις αναφορές. Για παράδειγμα μια πραγματική global μεταβλητή που εισάγετε μέσα σε μια εμβέλεια συνάρτησης με τη δήλωση 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) {
}
   

Μια παρόμοια συμπεριφορά εφαρμόζεται στη στατική δήλωση. Οι αναφορές δεν αποθηκεύονται στατικά:

<?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() για δεύτερη φορά.