Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is PHP static field real static?

Tags:

php

I feel that the PHP static field is static merely throughout a request.

I have this code in my controller class:

static $a = 2;

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

No matter how many times I request debug, it outputs:

int 2
int 3

Very different from my knowledge on static in java.

like image 810
bijiDango Avatar asked Mar 01 '26 14:03

bijiDango


1 Answers

Yes, static in PHP is "real" static.

What you observe is result of different application life cycle in PHP and Java.

In Java, web application run inside WebServer(HTTP server), which after initial class load, on following requests reuse what it already loaded. For this reason class(and static properties) initialization occurs only once in application life cycle.

In case of typical PHP web application it looks a bit different.

HTTP server is independent application which listens for HTTP requests and runs PHP on demand(not all HTTP requests must be passed to PHP). PHP is run as a separate process, request is passed and after answer is received process is discarded. Every request is handled by completely separate process. Classes(and static properties) are loaded and initialized from scratch every single time.

Below is simple(very) HTTP server written in PHP which will simulate how Java WebServer works.

<?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();

Run it using

php server.php HOST PORT

e.g.

php server.php 127.0.0.1 8080

Now open in your browser http://127.0.0.1:8080/static or http://127.0.0.1:8080/static2 and you will get

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

Number will be increasing as long as you don't restart server.

like image 178
mleko Avatar answered Mar 03 '26 02:03

mleko