The OP's question wasn't scoped to the mid-90s.
> PHP does not spawn a new OS process per request these days. It does spawn a new interpreter, but not a new OS process.
Like I said, the same holds true even for an OS thread. Anyway, if it's not a new OS process, then some sort of GC is needed, contrary to the OP's statement.
> Combined with the now bundled opcache, the re-work per request is limited to the developer's own initialization code if they don't choose to use a user-space shared cache.
Again, these are all solutions to problems PHP invented for itself. Other languages don't require special caching mechanisms; they get by on normal scoping rules and shared memory.
With PHP you can see your program as a pure function whose result depends only on arguments. You don't have to care about memory leaks like you don't have to do memory management when you have a GC. And if you want more performance and less convenience you can always opt into running your own web server.
> Don't use global variables
If you have an object that is persisted between requests you already have some state that is saved.
def __call__(self, request):
client_ip = request.META['REMOTE_ADDR']
self.last_visitors.append(client_ip)
...
This code follows your scoping rules but still leaks memory. So it looks like you don't understand why memory leaks occur. I explained somewhere in ancestor comment that to prevent leaks you either need a language with pure functions or reset environment on each request, none of which is possible in Python yet the latter is available for PHP users.With Django processing model any array can become the source of a memory leak. I have heard that Ruby and NodeJS developers often have to restart their applications every several hours because they even have no tools to find the source of a leak. The problem that does not exist in PHP by design.
True, but I'm not aware of any notable language that did it differently in the mid 1990's when PHP was rolled out. PHP does not spawn a new OS process per request these days. It does spawn a new interpreter, but not a new OS process. Combined with the now bundled opcache, the re-work per request is limited to the developer's own initialization code if they don't choose to use a user-space shared cache.