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.
with 0 CommentPHP 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.
with 0 CommentLaruence'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'.
with 0 CommentRunning '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.
with 0 CommentWhy $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.
with 0 CommentThe 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.
with 0 CommentWhy 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.
with 0 CommentWhy 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.
with 0 CommentRoot-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.
with 0 Comment