Question
How can I handle warnings produced by native PHP functions such as dns_get_record()?
array|false dns_get_record(
string $hostname,
int $type = DNS_ANY,
array &$authns = null,
array &$addtl = null
)
When a DNS query fails, the function may emit a warning. A try/catch block does not catch it because a PHP warning is not an exception.
Should I install an error handler, suppress or hide the warning and inspect the return value, or use another approach? What is the best practice?
Short Answer
PHP warnings and exceptions are separate error-reporting mechanisms. You will learn how to handle a warning from a single native-function call without globally changing application behavior, and how to use the function's documented return value as the primary result signal.
Concept
A PHP warning is a runtime diagnostic: PHP reports that something went wrong but usually allows the script to continue. An exception is an object that changes control flow until code catches it (or it reaches the top of the program).
try {
// This catches thrown Exception or Throwable objects.
} catch (Throwable $error) {
// A normal PHP warning does not arrive here.
}
Native functions commonly report recoverable failures in two ways:
- They emit a warning for diagnostic information.
- They return a special failure value, often
false.
For dns_get_record(), check its return value first. A failed query is represented by false; a successful lookup returns an array, which can be empty when the lookup succeeds but produces no matching records.
If the warning is expected and you need to prevent it from being displayed or logged, install a temporary, narrowly scoped error handler around only that call. The handler can turn the relevant warning into an ErrorException, which your normal try/catch code can handle.
This matters because warnings should not be silently ignored across an entire application. A scoped handler keeps the special treatment limited to the operation that expects the failure.
Mental Model
Think of a warning as a dashboard warning light and an exception as an emergency stop.
- A dashboard light tells you about a problem, but the car keeps moving. That is like a PHP warning.
- An emergency stop interrupts the journey until someone deals with it. That is like an exception.
try/catch is designed for emergency stops, not dashboard lights. A temporary error handler is like assigning someone to watch one particular warning light during one specific test drive and report it as an emergency if it appears.
Syntax and Examples
dns_get_record() returns either an array of records or false when it cannot complete the lookup.
<?php
$records = dns_get_record('example.com', DNS_A);
if ($records === false) {
echo 'The DNS lookup failed.';
} elseif ($records === []) {
echo 'The lookup completed, but no A records were returned.';
} else {
foreach ($records as $record) {
echo $record['ip'] . PHP_EOL;
}
}
Use strict comparison:
=== falsemeans the function reported failure.=== []means it returned a valid but empty array.
If you also need to intercept the warning, set a handler immediately before the call and restore the previous handler immediately afterward:
<?php
set_error_handler(
function (int $severity, string $message, string $file, int $line): never {
throw new ErrorException($message, 0, $severity, $file, $line);
},
E_WARNING
);
try {
$records = dns_get_record('invalid-hostname.example', DNS_A);
} catch (ErrorException $exception) {
$records = false;
error_log('DNS lookup warning: ' . $exception->getMessage());
} finally {
restore_error_handler();
}
The second argument, E_WARNING, limits this handler to warnings. The finally block is essential: it restores the previous handler whether the call succeeds or fails.
Step by Step Execution
Consider this helper that returns null rather than exposing PHP's warning behavior to the rest of an application:
<?php
function lookupARecords(string $hostname): ?array
{
set_error_handler(
function (int $severity, string $message, string $file, int $line): never {
throw new ErrorException($message, 0, $severity, $file, $line);
},
E_WARNING
);
try {
$records = dns_get_record($hostname, DNS_A);
return $records === false ? null : $records;
} catch (ErrorException $exception) {
return null;
} finally {
restore_error_handler();
}
}
Execution for a failing lookup:
set_error_handler()installs a handler forE_WARNINGonly.dns_get_record()attempts the DNS lookup.- PHP emits a warning instead of returning normally without diagnostics.
- The temporary handler receives that warning and throws an
ErrorException. - Control jumps to
catch, which returnsnullto represent a failed lookup. finallyruns even after the exception and restores the prior error handler.
Execution for a successful lookup:
- No warning is emitted.
dns_get_record()returns an array.- The helper returns that array.
finallyrestores the previous handler.
Real World Use Cases
Warnings from native functions often represent external or environment-dependent failures that an application can handle gracefully.
- DNS tools and monitoring: Show "lookup unavailable" instead of exposing a PHP warning to a visitor.
- Optional remote resources: Handle a temporary failure while reading data from an external service.
- File operations: Treat an unavailable optional file as a recoverable application condition while still logging it.
- Image and document processing: Convert a library warning into a clear validation error for an uploaded file.
- Legacy integrations: Wrap older PHP APIs that signal errors with warnings and
false, then expose a consistent application-level result.
For user-facing applications, do not display raw warnings in production. Log useful diagnostic details while returning a safe message or fallback result.
Real Codebase Usage
In real projects, developers usually isolate warning-producing APIs behind a small wrapper function. The rest of the code then works with predictable return values or domain-specific exceptions.
A common pattern is validation plus a guard clause:
<?php
function getMailServerRecords(string $domain): array
{
if ($domain === '') {
return [];
}
$records = dns_get_record($domain, DNS_MX);
if ($records === false) {
return [];
}
return $records;
}
When the warning itself must be controlled, keep the error handler inside the wrapper. This prevents unrelated warnings elsewhere in the request from being converted or suppressed.
A more expressive application design can throw a custom exception:
<?php
final class DnsLookupException extends RuntimeException
{
}
The wrapper can catch ErrorException, log technical details, and throw DnsLookupException. Controllers, commands, or API endpoints can then decide whether to retry, return a 503 response, or use cached data.
Use global error handlers for application-wide policies, such as central logging or converting selected PHP errors throughout the whole application. Do not install one merely to handle one expected call unless it is carefully scoped and restored.
Common Mistakes
Expecting catch to receive a warning
<?php
try {
dns_get_record('invalid-hostname.example');
} catch (Exception $exception) {
// Normal PHP warnings do not reach this block.
}
A warning is not automatically an Exception. Use the return value, or explicitly convert the selected warning with an error handler.
Forgetting to restore the error handler
<?php
set_error_handler($handler, E_WARNING);
$records = dns_get_record($hostname);
// The handler is still active for all later E_WARNING messages.
This can accidentally change how unrelated code behaves. Always use restore_error_handler() in finally.
Treating an empty array as failure
<?php
if (!$records) {
// This is true for both false and an empty array.
}
Use strict checks instead:
if ($records === false) {
// Failure.
}
Using @ as normal error handling
<?php
$records = @dns_get_record($hostname);
The @ operator hides diagnostics and can make debugging and monitoring harder. It also does not explain why failure occurred. Prefer documented return values, a scoped error handler when necessary, and logging.
Catching every PHP error indiscriminately
Converting all error levels into exceptions can change the behavior of dependencies and framework code. Restrict the handler to the relevant level, such as E_WARNING, and to the smallest possible code region.
Comparisons
| Approach | What it handles | Best use | Main caution |
|---|---|---|---|
| Check return value | The API's documented success or failure result | Most native PHP function calls | It may not stop the warning from being displayed or logged |
try/catch | Thrown Throwable objects | APIs that throw exceptions or errors | Does not catch ordinary PHP warnings by itself |
Scoped set_error_handler() | Selected PHP error levels during a small code region | Wrapping one warning-producing legacy/native call | Must restore the previous handler |
| Global error handler | Errors across the application | Central logging and consistent application policy | Can unexpectedly affect unrelated code |
@ error suppression | Display/reporting suppression for one expression | Rare legacy situations | Hides useful diagnostics; generally avoid |
A useful rule is: use the return value to decide the outcome; use a scoped handler only when you must control or transform the warning itself.
Cheat Sheet
// Primary result check
$records = dns_get_record($hostname, DNS_A);
if ($records === false) {
// Lookup failed
}
if ($records === []) {
// Lookup succeeded but returned no matching records
}
// Temporarily convert warnings into ErrorException objects
set_error_handler(
function (int $severity, string $message, string $file, int $line): never {
throw new ErrorException($message, 0, $severity, $file, $line);
},
E_WARNING
);
try {
$records = dns_get_record($hostname, DNS_A);
} catch (ErrorException $exception) {
// Handle warning as an exception
} finally {
restore_error_handler();
}
try/catchcatches thrownThrowableobjects, not ordinary warnings.- Check
=== false, notif (!$value), when an empty result is valid. - Limit an error handler with an error-level mask such as
E_WARNING. - Always restore a temporary handler in
finally. - Prefer logging and explicit failure handling over
@suppression.
FAQ
Can PHP try/catch catch warnings?
Not directly. Ordinary PHP warnings are not exceptions. A custom error handler can convert a warning into an ErrorException, which catch can then handle.
Does set_error_handler() handle every warning on the page?
It handles matching errors that occur while it is installed. If you install it only immediately around one call and restore it in finally, it affects only that small section of code.
Should I check dns_get_record() for false or an empty array?
Check both when the distinction matters. false means failure; an empty array is a successful call with no matching records returned.
Is it safe to hide PHP warnings in production?
Raw warnings should generally not be displayed to users in production. However, hiding output is not enough: handle the failure through return values or exceptions and log useful diagnostic information.
Should I use the @ operator with dns_get_record()?
Usually no. It suppresses useful diagnostics and makes failures harder to observe. A return-value check and, if needed, a scoped error handler are clearer.
Why use finally with restore_error_handler()?
finally runs whether the code succeeds, returns, or throws. It guarantees that later code does not accidentally keep using your temporary handler.
Should I catch Exception or Throwable in PHP?
When handling thrown values at an application boundary, Throwable is broader. For a handler that intentionally throws ErrorException, catching ErrorException is more precise.
Mini Project
Description
Build a small DNS lookup helper for a command-line script. The helper will convert a warning from dns_get_record() into a predictable null result, while preserving PHP's previous error handler after the lookup completes.
Goal
Create a function that returns IPv4 DNS records for a hostname or null when the lookup cannot be completed.
Requirements
- Accept a hostname as a string.
- Query only A records with
dns_get_record(). - Return an array for a successful lookup, including an empty array when no A records are returned.
- Return
nullif the lookup emits a warning or reportsfalse. - Limit warning conversion to the DNS lookup call.
- Restore the previous PHP error handler in all cases.
Keep learning
Related questions
Are PDO Prepared Statements Enough to Prevent SQL Injection in PHP?
Learn how PDO prepared statements prevent SQL injection in PHP, what they protect, and the mistakes that still leave MySQL apps vulnerable.
Can You Bind an Array to an IN Clause in PHP PDO?
Learn how PDO handles placeholders in IN() clauses, why arrays cannot be bound directly, and the safe PHP pattern to build dynamic queries.
Choosing the Right MySQL Collation for PHP and UTF-8
Learn how MySQL character sets and collations work with PHP, and how to choose a practical UTF-8 setup for web applications.