คำหลัก "คงที่" ภายในฟังก์ชัน?


110

ฉันกำลังดูแหล่งที่มาของ Drupal 7 และฉันพบบางสิ่งที่ฉันไม่เคยเห็นมาก่อน ฉันได้หาข้อมูลเบื้องต้นในคู่มือ php แต่ไม่ได้อธิบายตัวอย่างเหล่านี้

ไม่คำหลักอะไรstaticทำเพื่อตัวแปรภายในฟังก์ชันได้หรือไม่

function module_load_all($bootstrap = FALSE) {
    static $has_run = FALSE

คำตอบ:


155

ทำให้ฟังก์ชันจดจำค่าของตัวแปรที่กำหนด ( $has_runในตัวอย่างของคุณ) ระหว่างการโทรหลายสาย

คุณสามารถใช้สิ่งนี้เพื่อวัตถุประสงค์ที่แตกต่างกันตัวอย่างเช่น:

function doStuff() {
  static $cache = null;

  if ($cache === null) {
     $cache = '%heavy database stuff or something%';
  }

  // code using $cache
}

ในตัวอย่างนี้ifจะดำเนินการเพียงครั้งเดียว แม้ว่าจะมีการโทรหลายครั้งdoStuffก็ตาม


4
นอกจากนี้หากฟังก์ชันได้ทำงานครั้งเดียวฟังก์ชันนี้จะไม่รีเซ็ตค่า$cacheเป็นnullในการโทรในภายหลังใช่ไหม
user151841

7
@ user151841 $cacheจะถูกรีเซ็ตระหว่างคำขอเท่านั้น ใช่มันจะไม่ถูกรีเซ็ตในการโทร laters ในคำขอเดียวกัน (หรือการเรียกใช้สคริปต์)
Yoshi

14
@ มูฮัมหมัดเพราะนั่นเป็นเพียงสิ่งที่คำหลักคงทำ
Yoshi

2
ฉันเชื่อว่าการifตรวจสอบเงื่อนไข$cache === nullจะดำเนินการทุกครั้งที่มีการเรียกใช้ฟังก์ชันนี้คิดว่าจะไม่เรียกใช้รหัสบล็อก$cache = '..'หรือไม่
Aivaras

จะเกิดอะไรขึ้นถ้าฟังก์ชันเป็นวิธีการในคลาสตัวแปรคงที่ใช้ร่วมกันระหว่างอินสแตนซ์หรือไม่
santiago arizti

83

ดูเหมือนว่าจะไม่มีใครพูดถึงจนถึงตอนนี้ว่าตัวแปรคงที่ภายในอินสแตนซ์ต่างๆของคลาสเดียวกันยังคงเป็นสถานะ ดังนั้นโปรดใช้ความระมัดระวังในการเขียนรหัส OOP

พิจารณาสิ่งนี้:

class Foo
{
    public function call()
    {
        static $test = 0;

        $test++;
        echo $test . PHP_EOL; 
    }
}

$a = new Foo();
$a->call(); // 1
$a->call(); // 2
$a->call(); // 3


$b = new Foo();
$b->call(); // 4
$b->call(); // 5

หากคุณต้องการให้ตัวแปรคงที่จำสถานะของมันสำหรับอินสแตนซ์คลาสปัจจุบันเท่านั้นคุณควรยึดติดกับคุณสมบัติคลาสเช่นนี้:

class Bar
{
    private $test = 0;

    public function call()
    {
        $this->test++;
        echo $this->test . PHP_EOL; 
    }
}


$a = new Bar();
$a->call(); // 1
$a->call(); // 2
$a->call(); // 3


$b = new Bar();
$b->call(); // 1
$b->call(); // 2

1
อุ๊ย! นี่กัดฉันมากกว่าหนึ่งครั้ง ฉันคาดว่าสแตติกจะใช้กับอินสแตนซ์เท่านั้นโดยให้บันทึกช่วยจำ แต่นั่นเป็นวิธีคิดที่ผิดเพราะ "คงที่" ในบริบทของชั้นเรียนหมายถึงชั้นเรียนโดยรวม คุณสมบัติวิธีการและตัวแปร
systemovich

14

ให้ตัวอย่างต่อไปนี้:

function a($s){
    static $v = 10;
    echo $v;
    $v = $s;
}

สายแรกของ

a(20);

จะส่งออก10แล้วจะเป็น$v 20ตัวแปร$vไม่ใช่ขยะที่รวบรวมหลังจากฟังก์ชันสิ้นสุดลงเนื่องจากเป็นตัวแปรแบบคงที่ (ไม่ใช่ไดนามิก) ตัวแปรจะอยู่ในขอบเขตจนกว่าสคริปต์จะสิ้นสุดลงทั้งหมด

ดังนั้นการเรียกต่อไปนี้ของ

a(15);

แล้วออกจะ20แล้วตั้งให้เป็น$v15


9

แบบคงที่ทำงานเช่นเดียวกับในคลาส ตัวแปรนี้ใช้ร่วมกันในทุกอินสแตนซ์ของฟังก์ชัน ในตัวอย่างของคุณเมื่อเรียกใช้ฟังก์ชันแล้ว $ has_run จะถูกตั้งค่าเป็น TRUE การรันฟังก์ชันในอนาคตทั้งหมดจะมี $ has_run = TRUE สิ่งนี้มีประโยชน์อย่างยิ่งในฟังก์ชันเรียกซ้ำ (เป็นทางเลือกหนึ่งในการส่งผ่านการนับ)

ตัวแปรคงมีอยู่ในขอบเขตฟังก์ชันโลคัลเท่านั้น แต่จะไม่สูญเสียค่าเมื่อการเรียกใช้โปรแกรมออกจากขอบเขตนี้

ดูhttp://php.net/manual/th/language.variables.scope.php


3

ตัวแปรคงที่ในฟังก์ชันหมายความว่าไม่ว่าคุณจะเรียกใช้ฟังก์ชันกี่ครั้งก็ตามจะมีเพียง 1 ตัวแปรเท่านั้น

<?php

class Foo{
    protected static $test = 'Foo';
    function yourstatic(){
        static $test = 0;
        $test++;
        echo $test . "\n"; 
    }

    function bar(){
        $test = 0;
        $test++;
        echo $test . "\n";
    }
}

$f = new Foo();
$f->yourstatic(); // 1
$f->yourstatic(); // 2
$f->yourstatic(); // 3
$f->bar(); // 1
$f->bar(); // 1
$f->bar(); // 1

?>

3

เพื่อขยายคำตอบของยาง

หากคุณขยายคลาสที่มีตัวแปรแบบคงที่คลาสแบบขยายแต่ละคลาสจะมีสแตติกอ้างอิง "ของตัวเอง" ที่แชร์ระหว่างอินสแตนซ์

<?php
class base {
     function calc() {
        static $foo = 0;
        $foo++;
        return $foo;
     }
}

class one extends base {
    function e() {
        echo "one:".$this->calc().PHP_EOL;
    }
}
class two extends base {
    function p() {
        echo "two:".$this->calc().PHP_EOL;
    }
}
$x = new one();
$y = new two();
$x_repeat = new one();

$x->e();
$y->p();
$x->e();
$x_repeat->e();
$x->e();
$x_repeat->e();
$y->p();

ผลลัพธ์:

หนึ่ง: 1
สอง : 1
หนึ่ง: 2
หนึ่ง : 3 <- x_repeat
หนึ่ง: 4
หนึ่ง : 5 <- x_repeat
สอง : 2

http://ideone.com/W4W5Qv


1

ภายในฟังก์ชันstaticหมายความว่าตัวแปรจะคงค่าไว้ทุกครั้งที่มีการเรียกใช้ฟังก์ชันในช่วงชีวิตของการโหลดหน้า

ดังนั้นในตัวอย่างที่คุณได้รับถ้าคุณเรียกใช้ฟังก์ชันละสองครั้งถ้ามันตั้ง$has_runไปtrueแล้วฟังก์ชั่นจะสามารถที่จะรู้ว่ามันเคยถูกเรียกเช่นนี้เพราะ$has_runจะยังคงเท่ากับtrueเมื่อฟังก์ชั่นเริ่มต้นเป็นครั้งที่สอง

การใช้staticคำสำคัญในบริบทนี้มีอธิบายไว้ในคู่มือ PHP ที่นี่: http://php.net/manual/en/language.variables.scope.php

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.