55 < meta name ="viewport " content ="width=device-width, initial-scale=1.0 ">
66 < title > Modern PHP 8.x Masterclass — Complete Guide</ title >
77 < meta name ="description " content ="A comprehensive, modern guide to PHP 8.x programming covering beginner to advanced topics. ">
8+ < link rel ="icon " href ="favicon.ico " type ="image/x-icon ">
9+ < script >
10+ ( function ( ) {
11+ const stored = localStorage . getItem ( 'php-guide-dark-mode' ) ;
12+ const dark = stored ? stored === 'dark' : window . matchMedia ( '(prefers-color-scheme: dark)' ) . matches ;
13+ if ( dark ) document . documentElement . classList . add ( 'dark' ) ;
14+ } ) ( ) ;
15+ </ script >
816 < script src ="https://cdn.tailwindcss.com "> </ script >
917 < script defer src ="https://cdn.jsdelivr.net/npm/alpinejs@3.14.3/dist/cdn.min.js "> </ script >
1018 < script >
@@ -419,7 +427,7 @@ <h4 class="text-xl font-bold text-github-900 dark:text-github-100 flex items-cen
419427 < div class ="mt-4 space-y-4 text-github-700 dark:text-github-300 leading-relaxed ">
420428 < h5 class ="font-semibold text-github-900 dark:text-github-100 "> Conceptual Explanation</ h5 >
421429 < p > PHP provides < code class ="bg-github-100 dark:bg-github-800 dark:text-github-200 px-1 py-0.5 rounded text-sm font-mono "> for</ code > , < code class ="bg-github-100 dark:bg-github-800 dark:text-github-200 px-1 py-0.5 rounded text-sm font-mono "> while</ code > , < code class ="bg-github-100 dark:bg-github-800 dark:text-github-200 px-1 py-0.5 rounded text-sm font-mono "> do-while</ code > , and < code class ="bg-github-100 dark:bg-github-800 dark:text-github-200 px-1 py-0.5 rounded text-sm font-mono "> foreach</ code > . The < code class ="bg-github-100 dark:bg-github-800 dark:text-github-200 px-1 py-0.5 rounded text-sm font-mono "> foreach</ code > loop is the canonical tool for iterating arrays and objects implementing < code class ="bg-github-100 dark:bg-github-800 dark:text-github-200 px-1 py-0.5 rounded text-sm font-mono "> Traversable</ code > . By default it iterates over the array without modifying it; use < code class ="bg-github-100 dark:bg-github-800 dark:text-github-200 px-1 py-0.5 rounded text-sm font-mono "> foreach ($items as &$item)</ code > to mutate the original array in place.</ p >
422- < p > Modern PHP favors < strong > functional-style transformations</ strong > (< code class ="bg-github-100 dark:bg-github-800 dark:text-github-200 px-1 py-0.5 rounded text-sm font-mono "> array_map</ code > , < code class ="bg-github-100 dark:bg-github-800 dark:text-github-200 px-1 py-0.5 rounded text-sm font-mono "> array_filter</ code > ) or generators for large datasets instead of manual loops. The Zend Engine optimizes < code class ="bg-github-100 dark:bg-github-800 dark:text-github-200 px-1 py-0.5 rounded text-sm font-mono "> foreach</ code > over arrays efficiently by tracking an internal array pointer , but generators avoid materializing entire collections in memory.</ p >
430+ < p > Modern PHP favors < strong > functional-style transformations</ strong > (< code class ="bg-github-100 dark:bg-github-800 dark:text-github-200 px-1 py-0.5 rounded text-sm font-mono "> array_map</ code > , < code class ="bg-github-100 dark:bg-github-800 dark:text-github-200 px-1 py-0.5 rounded text-sm font-mono "> array_filter</ code > ) or generators for large datasets instead of manual loops. The Zend Engine optimizes < code class ="bg-github-100 dark:bg-github-800 dark:text-github-200 px-1 py-0.5 rounded text-sm font-mono "> foreach</ code > with copy-on-write iterators , but generators still avoid materializing entire collections in memory.</ p >
423431
424432 < h5 class ="font-semibold text-github-900 dark:text-github-100 pt-4 "> Idiomatic Code Example</ h5 >
425433 < div class ="rounded-lg bg-github-900 overflow-hidden text-sm my-4 ">
@@ -606,7 +614,7 @@ <h5 class="font-semibold text-github-900 dark:text-github-100 pt-4">Idiomatic Co
606614< span class ="line "> $rawEmail = $_POST['email'] ?? '';</ span >
607615< span class ="line "> $email = filter_var($rawEmail, FILTER_VALIDATE_EMAIL);</ span >
608616< span class ="line "> </ span >
609- < span class ="line "> if ($email === false || $email === null ) {</ span >
617+ < span class ="line "> if ($email === false) {</ span >
610618< span class ="line "> http_response_code(422);</ span >
611619< span class ="line "> echo 'Invalid email address.';</ span >
612620< span class ="line "> exit;</ span >
@@ -650,6 +658,7 @@ <h5 class="font-semibold text-github-900 dark:text-github-100 pt-4">Idiomatic Co
650658< span class ="line "> session_start();</ span >
651659< span class ="line "> </ span >
652660< span class ="line "> // After verifying credentials, rotate the session ID to prevent fixation</ span >
661+ < span class ="line "> // authenticateUser() is your credential-checking routine (returns int|null)</ span >
653662< span class ="line "> $userId = authenticateUser($_POST['email'] ?? '', $_POST['password'] ?? '');</ span >
654663< span class ="line "> </ span >
655664< span class ="line "> if ($userId !== null) {</ span >
@@ -1027,9 +1036,9 @@ <h5 class="font-semibold text-github-900 dark:text-github-100 pt-4">Idiomatic Co
10271036< span class ="line "> "phpunit/phpunit": "^10.5",</ span >
10281037< span class ="line "> "phpstan/phpstan": "^1.10"</ span >
10291038< span class ="line "> },</ span >
1030- < span class ="line "> "autoload": {
1039+ < span class ="line "> "autoload": {</ span >
10311040< span class ="line "> "psr-4": {</ span >
1032- < span class ="line "> "App\\\\ ": "src/"</ span >
1041+ < span class ="line "> "App\\": "src/"</ span >
10331042< span class ="line "> }</ span >
10341043< span class ="line "> },</ span >
10351044< span class ="line "> "autoload-dev": {</ span >
@@ -1438,7 +1447,7 @@ <h4 class="text-xl font-bold text-github-900 dark:text-github-100 flex items-cen
14381447 < div class ="mt-4 space-y-4 text-github-700 dark:text-github-300 leading-relaxed ">
14391448 < h5 class ="font-semibold text-github-900 dark:text-github-100 "> Conceptual Explanation</ h5 >
14401449 < p > The < strong > Zend Engine</ strong > compiles PHP scripts into bytecode (opcodes), executes them on a virtual machine, and manages memory through reference counting with a cycle-collecting garbage collector. Objects and arrays are reference-counted; when the count drops to zero, memory is reclaimed. Circular references are detected by the garbage collector.</ p >
1441- < p > < strong > OPcache</ strong > stores compiled bytecode in shared memory so that PHP does not recompile files on every request. It is the single most important performance extension for production PHP. PHP 8.0+ also includes a < strong > JIT (Just-In-Time)</ strong > compiler that translates hot bytecode into native machine code, significantly improving CPU-bound workloads.</ p >
1450+ < p > < strong > OPcache</ strong > stores compiled bytecode in shared memory so that PHP does not recompile files on every request. It is the single most important performance extension for production PHP. PHP 8.0+ also includes a < strong > JIT (Just-In-Time)</ strong > compiler that translates hot bytecode into native machine code; it can improve CPU-bound workloads, but typical I/O-bound web requests often see modest gains .</ p >
14421451
14431452 < h5 class ="font-semibold text-github-900 dark:text-github-100 pt-4 "> Idiomatic Code Example</ h5 >
14441453 < div class ="rounded-lg bg-github-900 overflow-hidden text-sm my-4 ">
@@ -1481,11 +1490,18 @@ <h5 class="font-semibold text-github-900 dark:text-github-100 pt-4">Idiomatic Co
14811490< span class ="line "> </ span >
14821491< span class ="line "> // Hash a password</ span >
14831492< span class ="line "> $hash = password_hash($plainPassword, PASSWORD_DEFAULT);</ span >
1493+ < span class ="line "> if ($hash === false) {</ span >
1494+ < span class ="line "> throw new RuntimeException('Password hashing failed.');</ span >
1495+ < span class ="line "> }</ span >
14841496< span class ="line "> </ span >
14851497< span class ="line "> // Verify on login</ span >
14861498< span class ="line "> if (password_verify($plainPassword, $hash)) {</ span >
14871499< span class ="line "> if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {</ span >
1488- < span class ="line "> $hash = password_hash($plainPassword, PASSWORD_DEFAULT);</ span >
1500+ < span class ="line "> $newHash = password_hash($plainPassword, PASSWORD_DEFAULT);</ span >
1501+ < span class ="line "> if ($newHash === false) {</ span >
1502+ < span class ="line "> throw new RuntimeException('Password rehashing failed.');</ span >
1503+ < span class ="line "> }</ span >
1504+ < span class ="line "> $hash = $newHash;</ span >
14891505< span class ="line "> // store updated hash</ span >
14901506< span class ="line "> }</ span >
14911507< span class ="line "> }</ span >
@@ -1494,8 +1510,8 @@ <h5 class="font-semibold text-github-900 dark:text-github-100 pt-4">Idiomatic Co
14941510< span class ="line "> $safe = htmlspecialchars($userInput, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');</ span >
14951511< span class ="line "> echo "<p>{$safe}</p>";</ span >
14961512< span class ="line "> </ span >
1497- < span class ="line "> // Secure headers</ span >
1498- < span class ="line "> header(' Content-Security-Policy: default-src \ 'self\'' );</ span >
1513+ < span class ="line "> // Secure headers. In production, serve inline scripts/styles with nonces/hashes instead of 'unsafe-inline'. </ span >
1514+ < span class ="line "> header(" Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'" );</ span >
14991515< span class ="line "> header('X-Frame-Options: DENY');</ span >
15001516< span class ="line "> header('Strict-Transport-Security: max-age=31536000; includeSubDomains');</ span > </ code > </ pre >
15011517 </ div >
@@ -1601,7 +1617,7 @@ <h5 class="font-semibold text-github-900 dark:text-github-100 pt-4">Common Anti-
16011617 @click ="goToPreviousModule() "
16021618 class ="flex-1 flex items-center justify-start gap-3 rounded-xl border border-github-200 bg-white px-5 py-4 text-left shadow-sm transition hover:border-php-300 hover:bg-php-50 dark:border-github-700 dark:bg-github-900 dark:hover:border-php-700 dark:hover:bg-php-900/20 "
16031619 >
1604- < svg class ="h-5 w-5 flex-shrink-0 text-github-400 dark:text-github-500 dark:text-github- 400 " fill ="none " stroke ="currentColor " viewBox ="0 0 24 24 "> < path stroke-linecap ="round " stroke-linejoin ="round " stroke-width ="2 " d ="M15 19l-7-7 7-7 "/> </ svg >
1620+ < svg class ="h-5 w-5 flex-shrink-0 text-github-400 dark:text-github-400 " fill ="none " stroke ="currentColor " viewBox ="0 0 24 24 "> < path stroke-linecap ="round " stroke-linejoin ="round " stroke-width ="2 " d ="M15 19l-7-7 7-7 "/> </ svg >
16051621 < div >
16061622 < span class ="block text-xs font-medium uppercase tracking-wider text-github-500 dark:text-github-400 "> Previous module</ span >
16071623 < span class ="block text-base font-semibold text-github-900 dark:text-github-100 " x-text ="previousModule ? previousModule.title : '' "> </ span >
@@ -1616,7 +1632,7 @@ <h5 class="font-semibold text-github-900 dark:text-github-100 pt-4">Common Anti-
16161632 < span class ="block text-xs font-medium uppercase tracking-wider text-github-500 dark:text-github-400 "> Next module</ span >
16171633 < span class ="block text-base font-semibold text-github-900 dark:text-github-100 " x-text ="nextModule ? nextModule.title : '' "> </ span >
16181634 </ div >
1619- < svg class ="h-5 w-5 flex-shrink-0 text-github-400 dark:text-github-500 dark:text-github- 400 " fill ="none " stroke ="currentColor " viewBox ="0 0 24 24 "> < path stroke-linecap ="round " stroke-linejoin ="round " stroke-width ="2 " d ="M9 5l7 7-7 7 "/> </ svg >
1635+ < svg class ="h-5 w-5 flex-shrink-0 text-github-400 dark:text-github-400 " fill ="none " stroke ="currentColor " viewBox ="0 0 24 24 "> < path stroke-linecap ="round " stroke-linejoin ="round " stroke-width ="2 " d ="M9 5l7 7-7 7 "/> </ svg >
16201636 </ button >
16211637 </ div >
16221638 </ nav >
0 commit comments