Press "Enter" to skip to content

Setting a Query Timeout for MySQL

Can you cap a slow query so it doesn't blow out PHP's max_execution_time? Yes — libmysql's MYSQL_OPT_READ_TIMEOUT (value 11, read from the enum), but only mysqli exposes mysql_options() to PHP, so you pass the numeric constant directly: $mysqli->options(11, 1). Laruence's catch: libmysql retries twice, so the effective timeout is 3x what you set — the practical floor is 3s.

Filed in English, MySQL/PostgreSQL, PHP应用, PHP源码分析
with 0 Comment

Using fastcgi_finish_request to Speed Up Page Responses

PHP FPM's fastcgi_finish_request() ends the client response and closes the connection but lets the PHP script keep running server-side — use it to defer logging, transcoding, or other post-render work off the critical path. Laruence's note: it's cleaner than flush() for this, and a function_exists() shim keeps the code portable to non-FPM environments.

Filed in English, PHP应用, 转载
with 0 Comment

PHP Internals — A Low-Probability Notice in Session GC

The occasional 'ps_files_cleanup_dir: opendir(/var/lib/php5) failed: Permission denied' Notice on apt/Debian PHP. Laruence traces it to the file_handler save handler's GC running on session_start: the default session dir is 733+sticky (root-owned, writable-but-not-listable by non-root workers), so s_gc's opendir() fails and fires an E_NOTICE. The check is rand < gc_probability/gc_divisor (default 1/100), so it's rare. Fix: set session.gc_probability=0 (Debian handles cleanup via an external cron), or fix the dir permissions.

Filed in English, PHP应用, PHP源码分析
with 0 Comment

Some PHP Coding Tips [last updated 2011-04-02]

Laruence's 17 hand-picked PHP performance/correctness tips: list() to skip explode() segments, NULL === over is_null, prefer === over ==, avoid continue, watch out for loose comparison in switch/in_array (strval the value, or pass a 3rd arg), use switch(TRUE) for if/elseif chains, define before use (undefined vars are 8x+ slower), swap without a temp, ~~ is ~3x faster than floor (but overflows on big numbers), do{}while(0) blocks, minimize @, avoid recursion, $_SERVER['REQUEST_TIME'] over time(), hoist strlen() out of the for-condition, prefer strncasecmp/strpbrk/stripos over regex, brace variables in double-quoted strings, and use FALSE for errors vs NULL for 'not found'.

Filed in English, PHP应用, 随笔
with 0 Comment

A Bug in PHP's Reflection Extension

Running 'php --re Dummy' on an extension whose module-entry function table lists a mixed-case function name (e.g. 'Dummy') triggers 'Internal error: Cannot find extension function Dummy in global function table'. Laruence traces it to the reflection extension's zend_hash_find on EG(function_table) not lowercasing func->fname first, while PHP's global function table is all-lowercase. Reported as bugs.php.net bug 54347.

Filed in English, PHP应用, PHP源码分析
with 0 Comment

The Leftover Problem with a Serializable Singleton — Answer

Why $a === Singleton::getInstance() is false after $a = unserialize(serialize($a)). Laruence walks the refcounting: unserialize runs __wakeup, which re-points self::$instance to the new object and drops the old instance's refcount to 1; the symbol $a still holds it; then reassigning $a drops that last reference, the old zval hits zero refcount and is freed, firing __destruct — which (in the naive version) resets self::$instance to NULL, clobbering the singleton. Fix: keep the cleanup in __destruct but don't reset $instance there.

Filed in English, PHP应用, PHP源码分析, 随笔
with 0 Comment

Serialize/Unserialize Breaks the Singleton

The usual Singleton (__construct/__clone private + static getInstance) silently breaks under serialize/unserialize — $a === $b is false after round-tripping. Two fixes: block it with private __sleep/__wakeup, or make it serialization-friendly by re-pointing self::$instance in __wakeup (and cleaning up in __destruct). Laruence plants a twist: even the 'friendly' version fails in a specific case, teased for the follow-up article.

Filed in English, PHP应用, 随笔
with 0 Comment

PHP Memory Management — Who Moved My Memory

Why memory_get_usage() doesn't drop back to baseline after unset($a). Laruence unpacks it: (1) PHP allocates memory implicitly (variable name in the symbol table + value), not only via explicit calls; (2) PHP's emalloc/efree don't hand memory to/from the OS — efree returns the chunk to PHP's own free/cache list, so real_size stays flat; (3) the 'missing' 32 bytes were actually consumed by an earlier var_dump's output header; (4) a HashTable only grows via resize and never shrinks, so the symbol table keeps its expanded size even after unsetting all variables.

Filed in English, PHP应用, PHP源码分析
with 0 Comment

Speeding Up PHP's ECHO

Why echoing large strings is slow (PHP blocks waiting for the write to complete, which is what inflates request time and piles up DB connections for slow clients) and the two-tier fix: PHP output buffering (ob_start / output_buffering — but only helps if the buffer is big enough) plus Apache's SendBufferSize so PHP hands the body to Apache and exits without waiting for the slow client. Laruence's caveat: it doesn't make the client faster, it just lets PHP release its resources sooner.

Filed in English, PHP应用, PHP源码分析
with 0 Comment

PHP Memory Management — Analyzing a Low-Probability Core

Root-causing a rare core in PHP 5.2.6's zend_alloc: a timeout signal fires mid-way through zend_mm_free_int, just before the line that clears a bit in free_bitmap (the HANDLE_BLOCK_INTERRUPTIONS() around it was a no-op before 5.2.17). The error handler then allocates memory for the 'Maximum execution time exceeded' message, reads the stale free_bitmap, hands out a bad self-pointing pointer, and ZEND_MM_CHECK_BLOCK_LINKAGE panics with 'zend_mm_heap corrupted'. A genuinely subtle interrupt-reentrancy corruption in the Zend memory manager.

Filed in English, PHP应用, PHP源码分析
with 0 Comment