Creating and using classes in Laravel

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Mastering Object-Oriented Programming in Laravel: Creating and Using Classes Effectively

As developers, moving from procedural scripting to Object-Oriented Programming (OOP) concepts—specifically classes—is a crucial step in building scalable, maintainable applications. In the context of a framework like Laravel, understanding how PHP's autoloading and namespaces interact with the framework’s structure is key to avoiding common errors.

Many developers run into issues when trying to place custom classes outside the standard app/ directory or misuse namespace declarations. This post will diagnose the issue you encountered and guide you through the correct, idiomatic way to create and utilize classes within a Laravel application, ensuring smooth integration with the framework’s powerful architecture.

Understanding PHP Namespaces and Autoloading

The error you encountered—Class 'App\myClasses\JunkFunction' not found—is fundamentally an issue of how PHP (and by extension, Laravel) finds class definitions. This is governed by namespaces and PSR-4 autoloading.

When you use a use statement in your controller:

use App\myClasses\JunkFunction;

You are telling PHP to look for the class definition within that specific namespace path. For this to work reliably, two conditions must be met:

  1. Correct File Structure: The physical directory structure must mirror the namespace structure. Laravel expects classes to reside within the app/ directory (or subdirectories thereof) to leverage its automatic discovery mechanism.
  2. Correct Class Definition: The class file itself must declare the correct namespace at the very top.

The Correct Laravel Approach: Leveraging PSR-4

The most robust way to handle custom classes in Laravel is to adhere to the conventions laid out by PSR-4 autoloading, which Laravel fully embraces. This means placing your custom classes inside the app directory and ensuring their namespaces map correctly to physical folders.

Step 1: Proper Directory Setup

Instead of creating a separate folder structure outside the standard application scope (like app/myClasses), you should place your custom logic within the standard structure, or organize it according to Laravel's expectations.

For example, if you want a class related to uploads, placing it inside app/Http/Controllers/ or perhaps in an app/Services/ directory is often cleaner than creating arbitrary subfolders under app/.

Let’s assume we place our service classes within the standard structure:

app/
├── Http/
│   └── Controllers/
│       └── UploadsController.php
└── Services/  <-- Recommended location for custom logic
    └── FileProcessor.php

Step 2: Defining the Class Correctly

In your class file, you must define a namespace that aligns with its physical location within the app directory. If you put it in app/Services/, the namespace should reflect that structure.

Example: app/Services/FileProcessor.php

<?php

namespace App\Services; // This maps to the 'Services' folder

class FileProcessor
{
    public function process(string $filePath)
    {
        // Implementation logic here
        return "File processed successfully.";
    }
}

Step 3: Using the Class in the Controller

Now, when using this class in your controller, you use a standard use statement based on the defined namespace. The magic of Laravel's container (Service Container) handles the dependency injection and object instantiation seamlessly.

Example: app/Http/Controllers/UploadsController.php

<?php

namespace App\Http\Controllers;

// Import the service class we just created
use App\Services\FileProcessor; 
use Illuminate\Http\Request;

class UploadsController extends Controller
{
    protected $fileProcessor;

    // Dependency Injection: Laravel automatically resolves this dependency
    public function __construct(FileProcessor $fileProcessor)
    {
        $this->fileProcessor = $fileProcessor;
    }

    public function handleUpload(Request $request)
    {
        $filePath = 'some/path/to/file.txt';
        
        // Use the injected class instance
        $result = $this->fileProcessor->process($filePath);

        return response()->json(['message' => $result]);
    }
}

Notice that in the controller, we no longer manually use new FileProcessor(). Instead, Laravel’s service container handles creating and injecting the necessary object based on the type-hinting. This is a core principle of building robust applications with Laravel; it promotes loose coupling and testability, which aligns perfectly with best practices promoted by organizations like the Laravel Company.

Conclusion

The difficulty in your initial attempt stemmed from mixing manual file placement with framework expectations regarding namespaces and autoloading. By adhering to PSR-4 standards—placing classes within app/ folders and ensuring their namespace matches that structure—you allow Laravel’s powerful autoloader to handle the discovery automatically. Embrace dependency injection and namespaces, and you will build applications that are not only functional but also clean, scalable, and easy for any developer to maintain.