Skip to content

ClassHelper

Mistralys edited this page Jun 29, 2022 · 13 revisions

This helper class is designed to be static analysis and refactoring-friendly when working with dynamic class names and composer autoloading.

Dynamic class names

When building class names dynamically, refactoring becomes difficult, and returning a specific class instance means you have to do a lot of instanceof calls, throwing exceptions if the object is not what you expected. The class has two methods for this:

Method requireObjectInstanceOf()

This method can be passed an object instance and the expected class name, and will throw an exception if the object is not an instance of this class. The return value is documented as returning an instance of that class for static analysis tools like PHPStan.

use AppUtils;

function getInstance() : ExpectedClassName
{
    // This is where the class name would be pieced together dynamically. 
    $class = 'Example\Dynamically\Built\ClassName';

    return ClassHelper::requireObjectInstanceOf(
        ExpectedClassName::class,
        new $class()
    );
}

It is also designed to write more concise code, which is easy to read.

Method resolveClassName()

This method is made specifically to work with legacy projects that mix class prefixes with namespaces, so for example:

Prefixes:   Example_Namespace_ClassName 
Namespaces: Example\Namespace\ClassName

Assuming the namespaces follow the same naming scheme, the method resolveClassName() will detect the actual class name being used, between the namespace or prefix style.

use AppUtils;

$class =  resolveClassName('Example_Namespace_ClassName');

This will return either Example_Namespace_ClassName or Example\Namespace\ClassName, depending on which is found, or NULL if none exist.

For compatibility with namespaces, this can be used interchangeably, even if the target class uses name prefixes:

use AppUtils;

$class = resolveClassName('Example\Namespace\ClassName');

Vendor and project names

With namespaces, it is customary to add the vendor name, which was not always the case with the prefix style. In this case, the method allows setting the vendor namespace prefix:

Prefixes:   Example_Namespace_ClassName
Namespaces: VendorName\ProjectName\Example\Namespace\ClassName;
$class = ClassHelper::resolveClassName('Example_Namespace_ClassName', 'VendorName\ProjectName');

It is recommended to use a constant for the vendor and project string, as it is not easily refactorable - this way, it stays easy to change when needed.

Checking classes

Method requireClassExists()

This simply checks if the target class exists, and throws an exception if it does not.

use AppUtils;

ClassHelper::requireClassExists('Example\Namespace\ClassName');

Method requireClassInstanceOf()

This simply checks if the specified class name extends or implements the target class or interface.

use AppUtils;

ClassHelper::requireClassInstanceOf(
    TargetClass::class,
    ExpectedInterface::class
);

Refactoring

Method name refactoring

Imagine having to reference an object method using a string: When renaming the method in the target class, the IDE will not know that this string must be updated too. Instead of using the method name without context, consider doing this:

// The IDE will recognise this as a callback, and will rename the method name automatically
$reference = array(ExampleClass::class, 'TargetMethodName');

// Store the method name
$methodName = $reference[1];

It can be further reduced to this:

$methodName = array(ExampleClass::class, 'TargetMethodName')[1];

Composer class loader

In a Composer project, the method getClassLoader() will return an instance of Composer's ClassLoader class, for advanced functionality.

New here?

Have a look at the overview for a list of all helper classes available in the package.

Table of contents

Find the current page in the collapsible "Pages" list above, and expand the page, to view a table of contents.

Clone this wiki locally