2016-12-29 107 views
2

我覺得PHP靜態字段在整個請求過程中都是靜態的。PHP靜態字段是否真實靜態?

我有我的控制器類的代碼:

static $a = 2; 

public function debug() 
{ 
    var_dump(self::$a++); 
    var_dump(self::$a++); 
} 

無論多少次,我請求debug,它輸出:

int 2 
int 3 

從Java中我的static知識有很大不同。

+3

靜態並不意味着不變。這意味着它屬於類而不是該類的實例化對象。至於「在整個請求中僅僅是靜態的」:每個請求都是PHP的一個新實例/線程,如果你想在請求中保存變量,你必須使用會話('__ SESSION')或某種其他存儲(數據庫,文件,...)。 – ccKep

+1

PHP中的靜態屬性與Java中的靜態屬性完全相同。 – Timurib

+1

@Amruthls。我認爲這是不同的問題。 ccKep提到的「每個請求都是PHP的新實例/線程」,可能是我的問題的答案。 – bijiDango

回答

1

是的,PHP中的靜態是「真實」的靜態。

您觀察到的是PHP和Java中不同應用程序生命週期的結果。

在Java中,Web應用程序在WebServer(HTTP服務器)內部運行,在初始類加載之後,以下請求重用它已加載的內容。由於這個原因,類(和靜態屬性)初始化在應用程序生命週期中只發生一次。

在典型的PHP Web應用程序中,它看起來有點不同。

HTTP服務器是一個獨立的應用程序,它監聽HTTP請求並按需運行PHP(並非所有的HTTP請求都必須傳遞給PHP)。 PHP作爲一個單獨的進程運行,請求被傳遞並且在接收到應答之後,進程被丟棄。每個請求都由完全獨立的進程處理。類(和靜態屬性)每次都從頭開始加載和初始化。

下面是簡單的(非常)用PHP編寫的HTTP服務器,它將模擬Java WebServer的工作方式。

<?php 

class Server { 
    private $socket; 
    private $routes = []; 

    public function __construct($address, $port, $backlog = 5) { 
     $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); 
     if ($socket === false) { 
      throw new Exception("socket_create() failed: reason: " . socket_strerror(socket_last_error($socket))); 
     } 
     if (socket_bind($socket, $address, $port) === false) { 
      throw new Exception("socket_bind() failed: reason: " . socket_strerror(socket_last_error($socket))); 
     } 
     if (socket_listen($socket, $backlog) === false) { 
      throw new Exception("socket_listen() failed: reason: " . socket_strerror(socket_last_error($socket))); 
     } 
     $this->socket = $socket; 
    } 

    public function listen() { 
     while(($requestSocket = socket_accept($this->socket)) !== false) { 
      $this->handleRequestSocket($requestSocket); 
     } 
     throw new Exception("socket_accept() failed: reason: " . socket_strerror(socket_last_error($this->socket))); 
    } 

    public function registerController($url, $controller) { 
     $this->routes[$url] = $controller; 
    } 

    private function handleRequestSocket($socket) { 
     $buffer = ""; 
     while(false !== ($part = socket_read($socket, 1024, PHP_NORMAL_READ))){ 
      $buffer .= $part; 
      if(substr($buffer, -4) == "\r\n\r\n") break; 
     } 
     $buffer = trim($buffer); 
     echo "\n======\n$buffer\n======\n"; 
     $response = $this->handleRequest($buffer); 
     if (null === $response){ 
      socket_write($socket, "HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n"); 
     } else { 
      socket_write($socket, "HTTP/1.1 200 OK\r\nContent-Length: ".strlen($response)."\r\n\r\n$response"); 
     } 
     socket_close($socket); 
    } 

    private function handleRequest($raw) { 
     $lines = explode("\r\n", $raw); 
     $req = explode(" ", $lines[0]); 
     $method = $req[0]; 
     $url = $req[1]; 

     if(isset($this->routes[$url])) { 
      return (string) (is_callable($this->routes[$url]) ? $this->routes[$url]($raw) : $this->routes[$url]); 
     } 
     return null; 
    } 
} 

class ControllerWithStatic { 
    private static $static = 0; 
    public function handle() { 
     return "Hello from static: " . (self::$static++) . "\n"; 
    } 
} 

$server = new Server($argv[1], $argv[2]); 

$c = new ControllerWithStatic(); 
$server->registerController("/", "Hello world\n"); 
$server->registerController("/closure", function(){return "Hello world from closure\n";}); 
$server->registerController("/static", [$c, 'handle']); 
$server->registerController("/static2", function(){ 
    return (new ControllerWithStatic())->handle(); 
}); 

$server->listen(); 

運行它使用

php server.php HOST PORT 

例如

php server.php 127.0.0.1 8080 

現在打開你的瀏覽器http://127.0.0.1:8080/statichttp://127.0.0.1:8080/static2,你會得到

Hello from static: 0 
Hello from static: 1 
Hello from static: 2 
... 

數量將只要你不重新啓動服務器增加。