skip to content

A PHP file needs Logger classes from two vendors, Acme\Log\Logger and Beta\Logging\Logger; how do you import both?

level: juniorimportance: should knowfreq 45%

answer

  1. one short name per file
  2. name is already in use error
  3. use ... as Alias
  4. alias the namespace instead of the class
  5. group use: use Acme\Log\{A, B};

basics

~10 s

Import one under an alias with as, for example use Beta\Logging\Logger as BetaLogger;. Importing both as Logger is a compile-time fatal error, because a short name can refer to only one class per file.

solid answer

~40 s

A `use` statement binds a **short name** to a full name for the rest of the file, and each short name can be bound once. Writing `use Acme\Log\Logger;` and `use Beta\Logging\Logger;` stops compilation with `Cannot use Beta\Logging\Logger as Logger because the name is already in use`. The fix is an alias: `use Beta\Logging\Logger as BetaLogger;`, then `new BetaLogger()`. Another option is to import the namespace, `use Beta\Logging;`, and write `Logging\Logger`. Aliases are purely compile-time: `BetaLogger::class` is still `Beta\Logging\Logger`, and the alias never leaves the file. A similar compile error appears when a file declares a class whose short name matches an import, and class-name comparisons are case-insensitive.

code

php · 17 lines
php
<?php
declare(strict_types=1);

namespace App\Audit;

use Acme\Log\Logger;
use Beta\Logging\Logger as BetaLogger;

final class DualLogger
{
    public function __construct(
        private Logger $primary,
        private BetaLogger $legacy,
    ) {}
}

echo BetaLogger::class; // Beta\Logging\Logger

go deeper

for a junior

Know the syntax: use Full\Name as Alias;, and that importing two classes under the same short name stops the file from compiling.

for a middle

Explain that an alias is a per-file compile-time entry, list the alternatives such as importing the namespace, and show group use with per-item aliases.

for a senior

Choose aliases that keep call sites readable, and remember that logs and stack traces show real names, so a reader must map aliases back when debugging.

for a principal

Treat recurring alias collisions as a design signal: an adapter behind one project-owned interface usually beats sprinkling two vendors' classes through the code.

## The problem Two libraries in the same project often ship classes with the same short name: `Logger`, `Client`, `Response`, `Collection`. Namespaces keep them apart as `Acme\Log\Logger` and `Beta\Logging\Logger`, but a file that needs **both** cannot import both under the name `Logger`. A `use` statement creates an entry in the file's **import table**: short name to full name. The table can hold one entry per short name, so this fails at compile time: ```php <?php namespace App\Audit; use Acme\Log\Logger; use Beta\Logging\Logger; // Fatal error: Cannot use Beta\Logging\Logger as Logger // because the name is already in use ``` Because it is an `E_COMPILE_ERROR`, nothing in the file runs; it is not an exception you can catch. ## Four ways out 1. **Alias one class** with `as`. This is the most common answer: `use Beta\Logging\Logger as BetaLogger;` then `new BetaLogger()`. 2. **Alias both**, when neither is the "main" one: `use Acme\Log\Logger as AcmeLogger;` and `use Beta\Logging\Logger as BetaLogger;`. 3. **Import the namespace** rather than the class: `use Beta\Logging;` makes `Logging\Logger` a qualified name whose first segment is translated, so it resolves to `Beta\Logging\Logger`. This also covers other classes in that namespace. 4. **Skip the import** and write the fully qualified name `\Beta\Logging\Logger` where it is used. This works but gets noisy if repeated. | Approach | Code at the call site | Good when | |---|---|---| | Alias one class | `new BetaLogger()` | one class is the primary one | | Alias both | `new AcmeLogger()`, `new BetaLogger()` | both are used equally | | Import the namespace | `new Logging\Logger()` | several classes from that namespace | | Fully qualified | `new \Beta\Logging\Logger()` | a single, rare reference | ## What an alias is and is not An alias is a **compile-time rename inside one file**: - It does not create a new class or type. `BetaLogger::class` evaluates to `'Beta\Logging\Logger'`, and `$x instanceof BetaLogger` checks the real class. - It is invisible outside the file. Another file importing the same class may use a different alias or none; error messages, stack traces and `get_class()` always show the real name. - It does not load anything. The import succeeds even if the class does not exist; failure comes only when code actually uses the class. - It is different from `class_alias()`, which registers a second, runtime name for a class for the whole process. ## Related conflicts - **Class declared in the same file.** `use Beta\Logging\Logger;` followed by `class Logger {}` in the same file is a compile error, "Cannot redeclare class App\Audit\Logger (previously declared as local import)"; in the opposite order the `use` line fails with "name is already in use". A class of that name in a different file of the same namespace does not conflict. - **Case-insensitivity.** Class names are case-insensitive, so `use Acme\Log\Logger;` and `use Beta\Logging\logger;` still collide. - **Separate tables.** Classes, functions and constants have separate import tables: `use Acme\Log\Logger;` and `use function Beta\Logging\logger;` can coexist. ## Group use declarations When several names come from one namespace, PHP 7.0 added **group use**, and PHP 7.2 allowed a trailing comma inside the braces: ```php <?php use Acme\Log\{Logger, LogLevel, Handler\StreamHandler as AcmeStream}; use function Acme\Log\{format_record, level_name}; use const Acme\Log\{DEFAULT_LEVEL}; ``` A plain group can also mix kinds with inline `function` and `const` markers: `use Acme\Log\{Logger, function format_record, const DEFAULT_LEVEL};`. Each item may carry its own alias, and each still counts against the one-short-name rule. ## Choosing alias names An alias is read far more often than it is written, so pick it for the reader: - Prefix with the **vendor or role**: `AcmeLogger`, `AuditLogger`, `LegacyLogger` all say where the class comes from. - Keep the real short name for the class the file uses most, and alias only the second one. - Avoid aliases that look like a different real class; `use Beta\Logging\Logger as Monitor;` hides what the object is. - Remember that stack traces, logs and `get_class()` show the **real** name, so someone debugging must map `BetaLogger` back to `Beta\Logging\Logger`. - If aliases for the same pair keep appearing across many files, hide one vendor behind an interface the project owns. ## Style notes Coding-style rules about import order and one import per statement belong to the project's standard, not to PHP. What the language itself guarantees is only that each short name is bound once per file and that the binding is resolved before the code runs.

  • In PHP, what is the difference between use Beta\Logging\Logger as BetaLogger; and class_alias()?
    `use ... as` is a compile-time rename that affects only the file it appears in; no new class name exists at run time. `class_alias('Beta\Logging\Logger', 'BetaLogger')` registers a second name for the class in the running process, so every file can refer to `\BetaLogger` and `class_exists()` sees it. The import is the normal tool; `class_alias()` is for migration shims.
  • In PHP, can use Acme\Log\Logger; coexist with use function Beta\Logging\logger; in one file?
    Yes. PHP keeps separate import tables for classes (and namespaces), functions and constants, so a class alias `Logger` and a function alias `logger` do not collide. Only two imports of the **same kind** under the same short name, compared case-insensitively for classes and functions, trigger the 'name is already in use' error.

saying these in an interview costs you the question

  • Two classes with the same short name can never be used in one file
  • An alias creates a new class name visible to the whole application
  • The second use statement silently overrides the first
  • The duplicate import throws an exception you can catch
  • An alias changes what ::class or get_class() returns