Passing a class as function parameter

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Passing a Class as a Function Parameter: Moving Beyond Simple Variables in PHP

As developers working within the Laravel ecosystem, we constantly grapple with how to structure our code to be flexible, testable, and maintainable. One common pattern that arises when dealing with dynamic tasks—like generating unique database slugs—is the desire to pass an entire class context into a helper function so it can perform complex operations against that context.

The initial attempt you presented:

php
function doSomething($param, Class) {
    Class::someFunction();
}
$someVar = doSomething($param, Class);

While conceptually appealing, this direct approach runs into limitations in standard PHP and object-oriented programming (OOP). The answer to "Is it possible?" depends heavily on what you intend for the function to receive: a class name (a string), an instance of a class, or a fully instantiated object.

Let's dive into why this direct approach is problematic and explore the correct, idiomatic ways to achieve your goal in a Laravel context.

The Problem with Passing Class Names

When you pass just the class name as a string, like Class, the function receives only text. To call $Class::someFunction(), PHP needs to resolve that string into an actual class reference at runtime. While this can be done using reflection or dynamic calls (like call_user_func), it is generally considered an anti-pattern in modern, strongly-typed languages like PHP, especially when dealing with complex application logic involving Eloquent models.

The core issue is that functions should operate on data or objects, not just strings representing types.

The Correct Approach: Dependency Injection and Object Passing

The most robust solution involves adhering to OOP principles by passing actual class instances (or interfaces) into your helper functions. This practice aligns perfectly with the principles championed by frameworks like Laravel, which heavily rely on dependency injection.

1. Passing Model Instances

If your helper function needs to query data related to a specific model (like Apk), you should pass an instance of that model, not just its name. This gives the function direct access to Eloquent relationships and methods.

Instead of:

php
// Attempting to pass context via class name
$helper->uniqueSlug($appname, Apk);

Do this: Pass the necessary Eloquent model instance:

php
use App\Models\Apk; // Assuming you are using Laravel's Eloquent models

class SlugHelper
{
    /**
     * Generates a unique slug based on database checks.
     * @param string $str The string to slugify.
     * @param Apk $model The specific model context needed for querying.
     * @return string
     */
    public function uniqueSlug(string $str, Apk $model): string
    {
        $slug = Str::slug($str);

        // Now we can safely query the database using the passed model instance
        $count = $model::whereRaw("slug RLIKE '^{$slug}(-[0-9]+)?$'")->count();

        return $count ? "{$slug}-{$count}" : $slug;
    }
}

2. Leveraging Laravel's Structure

In this refactored example, the uniqueSlug method no longer needs to worry about how to find the Apk model; it simply trusts that the object passed to it ($model) has the necessary database capabilities. This separation of concerns makes your code cleaner and easier to test—a key principle when building robust applications on Laravel.

When designing reusable logic, think about what data the function needs to operate, rather than what class it represents. If you need multiple models, consider defining an interface or a dedicated Service class to handle the complex interaction, which keeps your business logic separate from simple utility functions. For deeper architectural guidance on structuring these services within Laravel, exploring patterns found in documentation like https://laravelcompany.com is highly recommended.

Conclusion

Passing a class as a parameter should be replaced by passing instances of classes or defining interfaces. This shift moves your code from relying on fragile runtime string manipulation to leveraging the powerful structure of OOP. By embracing dependency injection and object orientation, you ensure that your