php runtime and server environment
Configuration Modes
This matters because not every php.ini setting can be changed with ini_set(). If you try to change a system-level directive from application code, it may silently fail or return false.
The Main Modes
You will see these mode names in PHP documentation:
INI_USER
INI_PERDIR
INI_SYSTEM
INI_ALL
Plain-English meaning:
INI_USER: can be changed in user scripts withini_set()INI_PERDIR: can be changed in per-directory or server configurationINI_SYSTEM: can be changed only in system-level configurationINI_ALL: can be changed anywhere supported
The mode belongs to the directive, not to your preference.
Checking A Runtime Change
ini_set() returns the old value on success or false on failure.
<?php
declare(strict_types=1);
$oldValue = ini_set('display_errors', '0');
if ($oldValue === false) {
echo 'display_errors could not be changed' . PHP_EOL;
} else {
echo 'display_errors changed from ' . $oldValue . ' to ' . ini_get('display_errors') . PHP_EOL;
}
This is a safe pattern when you need to know whether the change actually worked.
Runtime Settings
Some settings are commonly changed at runtime for a specific script or request.
<?php
declare(strict_types=1);
ini_set('memory_limit', '256M');
ini_set('display_errors', '0');
echo 'memory_limit=' . ini_get('memory_limit') . PHP_EOL;
echo 'display_errors=' . ini_get('display_errors') . PHP_EOL;
Use runtime changes sparingly. If a setting describes the environment, it usually belongs in php.ini, FPM pool config, container config, or deployment configuration.
System-Level Settings
Some settings must be changed before PHP starts or at the server configuration layer.
Examples include many extension-loading settings and low-level runtime settings.
extension=mbstring
zend_extension=opcache
opcache.enable=1
If a setting controls how PHP starts, loads extensions, or configures an engine-level feature, assume it probably does not belong in ini_set().
Per-Directory Configuration
Depending on the SAPI and server, PHP may support per-directory configuration.
Common places:
.user.inifor CGI/FastCGI-style setups where enabled.htaccesswith Apache module setups- web server configuration
- PHP-FPM pool configuration
Example .user.ini:
upload_max_filesize = 20M
post_max_size = 24M
Do not assume .user.ini is active everywhere. It depends on the SAPI and configuration.
PHP-FPM Pool Configuration
PHP-FPM can set PHP values at the pool level.
Example pool-style settings:
php_value[memory_limit] = 256M
php_admin_value[upload_max_filesize] = 20M
php_admin_value is stronger than php_value; application code cannot override admin values with ini_set().
This is useful for production control, but it can surprise developers who try to change a value from code and see no effect.
Inspecting Changeability
ini_get_all() can show access metadata for many directives.
<?php
declare(strict_types=1);
$settings = ini_get_all(null, false);
echo 'memory_limit=' . ($settings['memory_limit'] ?? 'unknown') . PHP_EOL;
echo 'display_errors=' . ($settings['display_errors'] ?? 'unknown') . PHP_EOL;
For exact changeability rules, use the PHP manual for the directive. In real debugging, combine documentation with a direct check: attempt the change, inspect the return value, and verify the resulting setting from the same SAPI.
Common Mistakes
Common configuration mode mistakes:
- assuming
ini_set()can change every directive - editing CLI
php.iniwhile debugging PHP-FPM - changing
.user.iniand expecting CLI scripts to see it - forgetting to reload PHP-FPM after config changes
- setting production rules in application code instead of deployment config
- assuming Apache
.htaccessrules apply to Nginx or Caddy
What You Should Be Able To Do
After this lesson, you should be able to explain what configuration modes are, recognise when ini_set() is appropriate, know where per-directory and system settings live, and verify whether a setting changed in the runtime that actually matters.
For junior PHP work, this matters because configuration bugs often come from changing a setting in the wrong place. The fix starts by knowing where that directive is allowed to change.
Practice
Practice: Test Whether A Directive Can Change
Create a small PHP diagnostic that attempts to change a runtime setting and reports whether it worked.
Task
Build a script that:
- prints the current SAPI
- prints the current
memory_limit - calls
ini_set('memory_limit', '256M') - checks whether
ini_set()returnedfalse - prints the final
memory_limit
Use strict types. Keep example output inside the PHP code block as comments.
Afterward, add a short note explaining why this test should be run in the same SAPI you are debugging.
Show solution
This diagnostic checks the return value from ini_set() instead of assuming the setting changed.
<?php
declare(strict_types=1);
if (PHP_SAPI !== 'cli') {
header('Content-Type: text/plain');
}
echo 'SAPI: ' . PHP_SAPI . PHP_EOL;
echo 'Before: ' . ini_get('memory_limit') . PHP_EOL;
$oldValue = ini_set('memory_limit', '256M');
if ($oldValue === false) {
echo 'Change result: failed' . PHP_EOL;
} else {
echo 'Change result: changed from ' . $oldValue . PHP_EOL;
}
echo 'After: ' . ini_get('memory_limit') . PHP_EOL;
// Prints:
// SAPI: cli
// Before: 128M
// Change result: changed from 128M
// After: 256M
Run this in the same SAPI you are debugging because CLI, FPM, Apache module, and the built-in server can have different configuration sources and different override rules.