Debugging PHP is mostly a matter of making the error visible to you and invisible to everyone else. The techniques are the same everywhere: report every error in development, log instead of display in production, inspect variables and the call stack, and use a step debugger when printing isn't enough. This guide covers each one for current PHP 8 versions, and what works on shared hosting versus your own machine.
In development, set error_reporting(E_ALL) and show errors; in production, keep display_errors off and read the log. Use var_dump(), error_log() and debug_print_backtrace() for quick checks, catch Throwable to log exceptions, and use Xdebug 3 with VS Code or PhpStorm on your own computer for breakpoints and step-through debugging. On Domain India shared hosting, errors are already logged by default, php_value lines in .htaccess cause a 500, and Composer can't run, so install developer tools locally.
1. Development and production need different settings
| Setting | Development | Production |
|---|---|---|
| error_reporting | E_ALL | E_ALL |
| display_errors | On | Off |
| log_errors | On | On |
| error_log | Any file you can read | A file outside the web root |
| zend.assertions | 1 | -1 |
Report everything in both places; what changes is where it goes. Displayed errors reveal file paths, queries and software versions, and they break JSON responses and redirects. On a live site, log them.
On your own computer or server, set these in php.ini, then restart PHP-FPM or your web server. On shared hosting you can't edit the server's php.ini; see section 8.
2. See the error for one script
For a quick look at a script you are working on, put this at the very top:
<?php
declare(strict_types=1);
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);Remove it when you have the message. A parse error in the same file stops PHP before these lines run, so check the log for those, or run php -l file.php on your computer to lint the file.
declare(strict_types=1) is not a debugging switch, but it turns many silent type conversions into clear TypeError exceptions, which makes bugs much easier to find.
3. Inspect variables
| Function | Shows | Best for |
|---|---|---|
| var_dump($x) | Type and value, nested | Checking exactly what a variable holds, including null, false and "" |
| print_r($x, true) | Readable structure, no types | A quick look at arrays and objects, or building a log line |
| var_export($x, true) | Valid PHP code | Copying a value into a test |
| json_encode($x, JSON_PRETTY_PRINT) | JSON | Logging data you will read elsewhere |
var_dump(false) and var_dump("") look different; print_r shows both as nothing, which is why var_dump is the safer first choice. In a browser, wrap the output in a pre block, or better, send it to the log so it never reaches visitors:
error_log('Order data: ' . print_r($order, true));4. Find how the code got there
When a function is called from somewhere unexpected, print the call stack:
function saveOrder(array $order): void
{
debug_print_backtrace(); // prints the stack to output
error_log((new \Exception())->getTraceAsString()); // or to the log
}debug_backtrace() returns the same information as an array if you want to filter it. Every exception also carries its own trace, which is usually the most useful thing to log.
5. Handle and log exceptions
Since PHP 7, most fatal errors are thrown as Error objects, so one handler catches both errors and exceptions through Throwable:
set_exception_handler(function (\Throwable $e): void {
error_log(sprintf(
'%s: %s in %s:%d%s%s',
$e::class, $e->getMessage(), $e->getFile(), $e->getLine(),
PHP_EOL, $e->getTraceAsString()
));
http_response_code(500);
echo 'Something went wrong. Please try again later.';
});Log the details, show the visitor a plain message. For structured logs with levels (info, warning, error), use a library such as Monolog rather than writing your own logger, and never log passwords, card data or full personal records.
A log written to public_html/logs/errors.txt can be downloaded by anyone who guesses the address. Write logs to a folder above the web root, such as your home folder, and never build a logger that passes user input to a shell command.
6. Step debugging with Xdebug 3
Printing values only goes so far. Xdebug lets you pause code at a breakpoint, inspect every variable and step line by line. Use it on your own computer or a development server, never on a live site: it slows every request.
A minimal Xdebug 3 configuration:
zend_extension=xdebug
xdebug.mode=debug
xdebug.start_with_request=trigger
xdebug.client_port=9003With start_with_request=trigger, Xdebug only activates when a request carries the trigger, set by a browser extension or the XDEBUG_TRIGGER variable, so normal requests stay fast. Xdebug 3 uses port 9003 by default, not 9000 as in older guides. In VS Code, install the PHP Debug extension and start "Listen for Xdebug"; PhpStorm has the same built in. xdebug.mode=profile writes profiles you can open in a profiler viewer, and xdebug.mode=develop improves var_dump() output.
Install Xdebug from your system's packages or PECL, matching your PHP version; Docker-based setups usually have it available as an option.
7. Useful developer tools
These install with Composer as development dependencies (composer require --dev …) on your own machine:
- Symfony VarDumper:
dump()anddd()with readable, collapsible output. - Whoops: a detailed error page with the stack trace and source, for development only.
- PHP Debug Bar: a toolbar showing queries, timing and memory for each request.
- PHPStan or Psalm: static analysis that finds type errors and undefined variables before you run the code.
- Laravel Telescope for Laravel applications; enable it in local development only.
For performance problems rather than errors, a profiler such as Blackfire or Xdebug's profile mode shows where the time goes.
8. Running this on Domain India
On Domain India cPanel and DirectAdmin shared hosting, the rules above apply with a few limits (on Webuzo, ask support):
- Errors are already logged. On our cPanel and DirectAdmin servers
display_errorsis off andlog_errorsis on by default. Look for anerror_logfile in the script's folder and, on cPanel,logs/yourdomain_com.php.error.login your home folder. Details: reviewing error logs. - Change settings with
.user.iniorini_set(), or the MultiPHP INI Editor on cPanel. Aphp_valueorphp_flagline in.htaccessmakes the site return a 500. See how to show PHP errors safely. - Test with a fresh query string such as
?t=1on cPanel, because a caching proxy can serve a stored page that never reaches PHP. - Some functions are disabled, including
exec,shell_exec,proc_openandpopen, so Composer can't run on shared hosting. Install dependencies on your computer and upload thevendorfolder. See PHP disabled functions. - Jailed SSH is available on every shared plan, off by default; ask support to enable it and log in with a key.
- WordPress has its own switches: how to enable debugging in WordPress.
For full control of php.ini, Xdebug and Composer on the server, a VPS is self-managed and lets you configure PHP however you need. The card shows the live price, excluding 18% GST.
- 25 GB NVMe SSD Storage
- 50 GB Monthly Bandwidth
- 1 Website
- 10 Email Accounts
How do I show PHP errors while debugging?
Add ini_set('display_errors', '1'); and error_reporting(E_ALL); at the top of the script, reload it, and remove the lines when you have the message. On a live site, read the error log instead of displaying errors.
What is the difference between var_dump and print_r?
var_dump shows the type and value of every element, so it distinguishes null, false and an empty string. print_r shows a simpler readable structure without types, and can return a string for logging when you pass true as the second argument.
Which port does Xdebug 3 use?
Xdebug 3 connects to your IDE on port 9003 by default. Older Xdebug 2 guides use port 9000, which no longer applies.
Should I use Xdebug on a live website?
No. Xdebug slows every request and is meant for development. Use it on your own computer or a development server, and rely on error logs in production.
Where are PHP errors logged on Domain India shared hosting?
On our cPanel and DirectAdmin servers, errors are logged by default to an error_log file in the script's folder and, on cPanel, also to logs/yourdomain_com.php.error.log in your home folder.
Can I run Composer on Domain India shared hosting?
No. Composer needs PHP functions that are disabled on our shared servers. Run Composer on your computer and upload the vendor folder, or use a VPS.
Ready to track down the bug? Start with the log, or open a support ticket with the page address and the time it failed if you can't find the error.
Send us the page address, the time of the error and what you changed last, and we will read your account's logs with you.
Open a support ticket