据我所知,对于连接到服务器的每个客户端,PHP都会为它生成一个新线程。 但是我想知道它是否真实,如果它是真的,这个线程能保持多久? 该线程是否正确维护所有静态变量? (就像数据库连接一样)
当这个线程被破坏时,它是否会调用所有的析构函数?
答案 0 :(得分:8)
这完全取决于如何使用服务器设置PHP。我更熟悉Apache / PHP组合(而不是用PHP设置说Nginx和FastCGI),所以关注这个领域:
PHP通常作为DSO(动态共享对象)模块集成到Apache中。
现在,通常在Linux / Unix下的Apache通常被设置为“预分叉”模型 - 即当它启动时,会分叉一堆子进程(确切的数字可以通过Apache指令配置),他们正处于准备处理请求的“流程池”中。
当请求到达时,内核调度程序从池中选择一个Apache进程(如果可用),并且请求由子进程处理。
基于Apache设置,如果它检测到需要执行PHP脚本,则按照(1)中的设置将其交给PHP DSO。
因此,在每个请求的基础上不涉及分叉或线程,这是有效的。所有请求上下文都传递给PHP层,后者开始编译并执行PHP脚本。
注意:如果启用了操作码缓存,则可以绕过编译步骤 - 即编译PHP脚本上的第一个请求,并缓存其关联的操作码以便为后续请求重用(它是全局的所有子进程共享的缓存)。由于编译步骤很昂贵(解析脚本等等),对于生产系统,最好启用操作码缓存。
当PHP脚本完成时,它进入清理例程(内置于PHP DSO),它将清理每个请求内存,关闭所有文件描述,包括db句柄(基于如何它被打开了)。一些PHP方法具有“持久”句柄(例如,打开数据库连接,文件句柄),这些句柄可以跨请求保存,因此您用于打开特定资源的功能很重要(其各自的文档突出显示)。默认情况下,大多数资源仅在PHP请求的生命周期中保留,并且在PHP请求完成后会被销毁。
关于PHP对象dtors,它取决于创建对象的范围。因此,对于全局对象,其dtors将仅在请求周期结束时被调用,而其中一些将在函数返回时超出范围时被调用。
因此,您获得了内存/资源mgmt是免费的。您可以通过unset()调用立即触发空闲来控制它。同样从PHP 5.3开始,也可以在请求处理阶段启用垃圾收集 - 请在此处查看更多详细信息:http://www.php.net/manual/en/features.gc.php
现在,这个Apache子程序(运行PHP脚本)重新进入准备好处理下一个请求的进程池,如步骤3所示。
上面描述的内容对于Linux / Unix环境中的Apache / PHP来说是典型的,但我认为类似的情况也适用于Microsoft设置。
同样使用nginx和FastCGI + PHP,我认为同样的循环也适用 - 即在PHP + FastCGI模块处理的请求周期结束时清理事物。这也是当nginx启动时,它将启动由FastCGI + PHP模块处理的单独进程池,并且nginx和FastCGI + PHP之间的通信发生在unix套接字中。
希望这有帮助。
答案 1 :(得分:5)
它不是PHP,而是处理请求的Web服务器。 PHP本身并不运行。如果网页包含PHP代码,则此类请求将由适当的PHP SAPI模块委派给PHP。有多线程,多进程的Web服务器,甚至可以想象单进程Web服务器,因此如果为请求创建单独的线程或进程,它纯粹依赖于Web服务器。
在许多PHP文档中,您可以在umask()
上遇到类似这样的行:
避免在多线程Web服务器中使用此功能。它更好 创建文件后,使用chmod()更改文件权限。 使用umask()可能会导致并发运行的意外行为 脚本和Web服务器本身,因为它们都使用相同的umask。
...这个帖子能活多久?该线程是否正确维护所有静态变量? (比如数据库连接)
你听起来像是一个有C ++背景的人。你可能在PHP中指的是全局变量。 PHP内置了对数据库连接的支持,你不必担心这些事情。它们是实现细节。大多数SAPI提供持久的数据库连接,但这只是为了您的好奇心。每个进程创建一个持久连接,用于处理请求。所以在这种情况下,它们由一个进程而不是一个进程来维护。
当此线程被销毁时,它是否会调用所有析构函数?
在PHP中,在脚本完成执行时调用析构函数。从PHP开发人员的角度来看,脚本所处的位置无关紧要。