Every year, Laravel receives an upgrade. As new features arise, old ones phase out, leading to ongoing changes. So, the farther ahead you are from the latest version, the more challenging and time-consuming it becomes to upgrade compared to staying up-to-date with regular upgrades. The main reason for this problem is letting your codebase become too large. As classes, methods and functions become more reliant on each other, making significant changes becomes much more difficult. Ever since Laravel 10 was launched, support and maintenance for Laravel 8 have ceased. The sooner your project gets an upgrade, the better things will turn out.
In this blog post, we’ll guide you through the process of upgrading your project from Laravel 8 to Laravel 10. This guide covers manual upgrades. Hence, if you seek an automated fix, consider utilizing Laravel Shift (note: it’s a paid service).
Table of Contents
Introduction to the New Features of Laravel 10
1. Laravel Pennant
This latest package, included in Laravel 10, provides a feature flagging feature for your application. When you mark a feature, it will be deemed either accessible or inaccessible. Let’s say your application has a “meeting booking” feature and this feature is only available for users whose role is “boss”. You can handle the availability of that feature as follows:
How to Use Pennant
- Define a Feature Flag:
Feature::define(‘meeting-booking’, fn (User $user) => $user->isBoss());
- Check Feature Availability:
if (Feature::active(‘meeting-booking’)) {
$this->meetingBookingNow($data);
}
- Control Blade Template Rendering:
@feature(‘meeting-booking’)
@endfeature
2. Process Interaction
In Laravel 10.x, a new feature called the Process facade simplifies and enhances interaction with external operations. It introduces a streamlined abstraction layer allowing users to execute commands within the application or mimic actions for testing purposes.
For example, you can use the run method to execute commands like ‘ls -la’:
$result = Process::run(‘ls -la’);
Additionally, you can concurrently run multiple commands using the concurrently method:
[$first, $second, $third] = Process::concurrently(function (Pool $pool) {
$pool->command(‘cat first.txt’);
$pool->command(‘cat second.txt’);
$pool->command(‘cat third.txt’);
});
To simulate a process call for testing purposes, you can utilize the fake method:
Process::fake();
Moreover, the assertRan method helps in verifying if a particular command was executed:
Process::assertRan(‘ls -la’);
This functionality provides a convenient way to manage and interact with external processes within Laravel applications.
3. Test Profiling
The Artisan test command now includes a new –profile option making it simpler to identify the slowest tests within your application.
php artisan test –profile
To make things easier, the CLI output will show the slowest tests directly.
(source: https://laravel.com/)
4. Pest Scaffolding in Laravel
Pest, a PHP testing framework offered by PHPUnit is now supported in Laravel for testing purposes. In new Laravel projects, Pest test scaffolding can be automatically included by default. To enable this feature during the creation of a new application using the Laravel installer, simply add the ‘–pest’ flag:
laravel new example-application –pest
Introduction to the New Features of Laravel 9
1. Simplified Accessors and Mutators
“Accessors and Mutators” also known as “getters and setters” have traditionally been declared in Laravel using a prefix attached to the attribute name. For example, the methods getXAttribute() and setXAttribute() have been used for this purpose. While these methods will still be supported, there’s a newer & simpler approach that will be recommended moving forward:
// Traditional approach
public function getNameAttribute($value)
{
return strtoupper($value);
}
public function setNameAttribute($value)
{
$this->attributes[‘name’] = $value;
}
// New method for declaring getters and setters
public function name(): Attribute
{
return new Attribute(
get: fn ($value) => strtoupper($value),
set: fn ($value) => $value,
);
}
2. Enum Attribute Casting
With the introduction of enum class support in PHP 8, Laravel 9 has undergone updates to accommodate Eloquent attribute casting to and from an enum object. This allows for the declaration and utilization of enums within your code.
For example, you can define an enum like this:
enum Status: string {
case DRAFT = ‘draft’;
case PUBLISHED = ‘published’;
case ARCHIVED = ‘archived’;
}
In your Eloquent model, you can specify attribute casting using the $casts property:
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
‘status’ => Status::class,
];
This setup enables operations such as changing a post’s status and saving the updated status:
if ($post->status === Status::DRAFT) {
$post->status = Status::PUBLISHED;
}
$post->save();
The enhancements in Laravel 9 utilize PHP 8’s enum support enabling better and more expressive management of attributes in Eloquent models.
3. Implicit Route Bindings With Enums
This functionality enables you to associate a request’s parameter with an enum. Suppose you create an enumeration and then proceed to bind it as shown below. With this binding, any request that passes a value that is not a valid enum will lead to an HTTP 404 response. This is convenient since you no longer have to check it in controllers:
enum Category: string
{
case Fruits = ‘fruits’;
case People = ‘people’;
}
Route::get(‘/categories/{category}’, function (Category $category) { return $category value; });
4. Forced Scoping Of Route Bindings
In earlier versions of Laravel, it was possible to specify that the second Eloquent model in a route had to be a child of the preceding model. For example, consider this route definition, fetching a blog post by slug for a specific user:
use App\Models\Post;
use App\Models\User;
Route::get(‘/users/{user}/posts/{post:slug}’, function (User $user, Post $post) {
return $post;
});
When defining the route this way, Laravel attempted to determine the foreign key based on predefined conventions. But to make it recognize the need for a second model binding, you had to define a custom key binding for :slug.
However, in the updated version, calling scopeBindings() achieves the identical result.
use App\Models\Post;
use App\Models\User;
Route::get(‘/users/{user}/posts/{post}’, function (User $user, Post $post) {
return $post;
})->scopeBindings();
// You can instruct a group of route definitions to use scoped bindings:
Route::scopeBindings()->group(function () {
Route::get(‘/users/{user}/posts/{post}’, function (User $user, Post $post) {
return $post;
});
});
This streamlines the process making it unnecessary to define custom bindings for individual route models explicitly.
5. Controller Route Groups
You can now organize routes by a controller using the example below:
Route::controller(OrderController::class)->group(function () {
Route::get(‘/orders/{id}’, ‘show’);
Route::post(‘/orders’, ‘store’);
});
This allows you to group routes under a specific controller making your code more organized and manageable.
6. Full-Text Indexes / Where Clauses
Incorporating full-text indexes into your queries can be done using methods like whereFullText() and orWhereFullText() for performing comprehensive text searches.
For example, in your migration file you can define a full-text column like this:
$table->text(‘bio’)->fullText();
Then, executing a full-text search query can be as simple as this:
$users = DB::table(‘users’)->whereFullText(‘bio’, ‘web developer’)->get();
This code fetches users where the ‘bio’ column contains the term ‘web developer’.
7. Laravel Scout Database Engine
The main aim of Laravel Scout lies in streamlining the full-text search within your project. It operates as a driver-based solution enabling compatibility with various engines like Elasticsearch, Algolia, MeiliSearch, MySQL, PostgreSQL and others through the Scout API.
Its core function involves making the search() method accessible for your Eloquent model. It also automatically handles indexing upon data input. However, note that the search() method doesn’t support intricate queries like Elasticsearch DSL. Consequently, Scout is best suited for smaller or medium-scale projects. Consider the example below:
// Example of using search() within ‘title_en’
$posts = Post::search($request->get(‘search’))->within(‘title_en’)->get();
// You can also paginate the result
$posts = Post::search($request->get(‘search’))->paginate(10);
The Laravel Scout feature streamlines search functionality and indexing management, but it’s better suited for simpler projects due to its limitations.
8. Rendering Inline Blade Templates
Rather than setting up your template in a .blade.php file you have the option to directly render it using Blade::render(). This proves beneficial when making an AJAX call to fetch a partial view for your SPA (Single Page Application) usage.
Here’s an example:
use Illuminate\Support\Facades\Blade;
// Inline Blade rendering
return Blade::render(‘Hello, {{ $name }}’, [‘name’ => ‘Julian Bashir’]);
// Rendering a component inline
return Blade::renderComponent(new HelloComponent(‘Julian Bashir’));
This allows for more dynamic rendering especially in scenarios where immediate access or modification of templates is necessary.
9. Slot Name Shortcut
Slot names were previously indicated in Laravel using a name attribute within the x-slot tag. However, starting from Laravel 9.x, a more concise and convenient syntax is available to specify the slot’s name:
Old way:
<x-alert>
<x-slot name=”title”>
Server Error
</x-slot>
<strong>Whoops!</strong> Something went wrong!
</x-alert>
New way:
<x-alert>
<x-slot:title>
Server Error
</x-slot>
</x-alert>
This newer approach simplifies the naming process for slots in Laravel components.
10. Enhanced Validation for Nested Array Data
At times, you might want to retrieve a specific value within a nested array element when setting validation rules for an attribute. Now, you can achieve this by utilizing the Rule::forEach() method.
Here’s an example:
$validator = Validator::make($request->all(), [
‘companies.*.id’ => Rule::forEach(function ($value, $attribute) {
return [
Rule::exists(Company::class, ‘id’),
new HasPermission(‘manage-company’, $value),
];
}),
]);
This setup allows you to access and validate individual values within nested arrays while defining your validation rules.
11. Laravel Breeze API & Next.js
The Laravel Breeze starter kit now includes an “API” scaffolding mode and a compatible Next.js frontend setup. This scaffolding option is designed to help kickstart your Laravel applications acting as a backend providing a Laravel Sanctum authenticated API for your JavaScript frontend.
12. Bundling with Vite
In addition to new features, the process of bundling your project assets in Laravel has shifted from utilizing Mix webpack to Vite.
13. Enhanced Ignition Exception Page
We’ve completely revamped the exception debug page. The new and improved version aims to help you in debugging more easily and efficiently.
(source: https://laravel.com)
Security Vulnerabilities Addressed in the Updated Version
- Preventing the Upload of .phar Files
Laravel enhances security by blocking the upload of executable PHP files. This includes files with extensions such as ‘.php’, ‘.php3’, ‘.php4’, ‘.php5’, ‘.php7’, ‘.php8’, ‘.phtml’ and now, ‘.phar’, which has been added to further bolster security measures.
- SQL Injection in SQL Server
There was a vulnerability in Laravel related to SQL Injection in SQL Server. This vulnerability allowed SQL Injection attacks when directly passing user input to the limit() and offset() functions in SQL Server. It’s important to note that this vulnerability did not affect other database drivers like MySQL and Postgres.
- SQL Injection – Binding Query Parameter Using an Array
The code below is vulnerable to a SQL Injection attack. This vulnerability arises because of incorrect binding when passing an array ($value = [1,1]) to the where() method causing the is_admin value to be 1 instead of 0.
User::where(‘id’, [1,1])->where(‘is_admin’, 0)->first();
// sql: select * from `users` where `id` = 1 and `is_admin` = 1
However, this information has been addressed in the update. The query string will now appear as follows:
// sql: select * from `users` where `id` = 1 and `is_admin` = 0
In the previous section, we’ve discussed the new features of Laravel 9 and 10 along with the addressed security vulnerabilities. Now, let’s guide you through upgrading your Laravel project from version 8 to 10.
Migrate Your Project From Laravel 8 to Laravel 10
Upgrade to PHP 8.1.0 & Composer 2.2.0:
As Laravel 10 mandates PHP 8.1.0 as a minimum requirement, upgrading to PHP 8.1.0 is necessary. Additionally, Composer needs to be upgraded to version 2.2.0 or higher. This step is extremely important and must be done before moving on to the next section.
Modify your dependencies within the composer.json file.
Upgrade Instructions for Package Versions:
Please review the list below to identify packages that need updating to their newer versions. Follow the provided instructions to ensure a successful update in your composer.json file.
General Package Updates:
Update the versions of the following packages in your composer.json file:
{
“require”: {
“php”: “^8.1”,
“laravel/framework”: “^10.0”,
“laravel/sanctum”: “^3.2”,
“doctrine/dbal”: “^3.0”,
“laravel/passport”: “^11.0”
},
“require-dev”: {
“nunomaduro/collision”: “^6.1”,
“spatie/laravel-ignition”: “^2.0”
}
}
Broadcasting Feature Update:
If your project utilizes the Broadcasting feature, update the version of pusher/pusher-php-server to “^5.0” in your composer.json file.
Storage Driver Updates (S3, FTP, SFTP):
If you employ S3, FTP or SFTP drivers through Storage, update the versions of the following items:
{
“require”: {
“league/flysystem-aws-s3-v3”: “^3.0”,
“league/flysystem-ftp”: “^3.0”,
“league/flysystem-sftp-v3”: “^3.0”
}
}
PHPUnit 10 Compatibility:
To use PHPUnit 10, follow these steps:
- Remove the processUncoveredFiles=”true” attribute from the <coverage> section of your application’s phpunit.xml configuration file.
- Update the following dependencies in your application’s composer.json file:
{
“require-dev”: {
“nunomaduro/collision”: “^7.0”,
“phpunit/phpunit”: “^10.0”
}
}
Make sure you accurately implement these changes to stay compatible and take advantage of the newest features and enhancements provided by these packages.
Removed packages:
Feel free to delete these packages as they are no longer necessary or in use.
Trusted Proxies:
To adjust your Trusted Proxies settings, go to the file located at
app/Http/Middleware/TrustProxies.php and make the following updates:
Change the namespace reference from:
use Fideloper\Proxy\TrustProxies as Middleware;
To:
use Illuminate\Http\Middleware\TrustProxies as Middleware;
Update the $headers property definition within the TrustProxies.php file:
Change:
protected $headers = Request::HEADER_X_FORWARDED_ALL;
to:
protected $headers =
Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_HOST |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO |
Request::HEADER_X_FORWARDED_AWS_ELB;
Ultimately, eliminate the “fideloper/proxy” package from your application by deleting the specified lines from your composer.json file.
{
“require”: {
// Remove this package
“fideloper/proxy”: “^4.4”
}
}
Fruitcake/laravel-cors:
The Fruitcake/laravel-cors package has been discontinued and removed from Laravel 10. To adjust, modify the namespace for the HandleCors middleware in app\Http\Kernel.php.
Change:
\Fruitcake\Cors\HandleCors::class
to:
\Illuminate\Http\Middleware\HandleCors::class
Also, eliminate the package from your composer.json file by erasing the following lines:
{
“require”: {
// Remove this package
“fruitcake/laravel-cors”: “^2.0”
}
}
Packages Replacement:
Replace these items in composer.json with their respective replacements.
{
“require-dev”: {
// Replace this
“facade/ignition”: “^2.5”
// With this
“spatie/laravel-ignition”: “^1.0”
}
}
To use Laravel’s SMS Notifications, remember that Nexmo is now under Vonage. Update your composer.json file accordingly.
{
“require”: {
// Replace this
“laravel/nexmo-notification-channel”: “^2.0”
// With this
“laravel/vonage-notification-channel”: “^3.0”
}
}
Swift Mailer is replaced with Symfony Mailer:
Laravel 9.x introduces a major update by replacing the outdated Swift Mailer, which ceased updates in December 2021, with Symfony Mailer. To perform the update, run the following commands:
Remove SwiftMailer:
composer remove wildbit/swiftmailer-postmark
Require Symfony Mailer components:
composer require symfony/mailgun-mailer symfony/postmark-mailer symfony/http-client
Run “composer update” command:
After modifying the composer.json file, run the “composer update” command. Please be aware that the packages listed are designed specifically for essential Laravel functionalities. Hence, it’s crucial to ensure updates for all other dependencies your project uses to prevent clashes with Laravel’s dependencies.
Once the command has been executed successfully, move on to update your source code by removing outdated features. This stage guarantees the smooth operation of your project. Also, take the opportunity to discover and integrate new features that have been introduced in the latest version of Laravel.
Configuration Changes
Change the ‘schema’ setting in your config/database.php file to ‘search_path’ to configure the Postgres database.
‘connections’ => [
‘pgsql’ => [
// replace this
‘schema’ => ‘public’,
// by this
‘search_path’ => ‘public’,
]
]
If you’re using SFTP via Laravel Storage, you’ll need to modify the config/filesystems.php file.
‘sftp’ => [
// Replace this
‘password’ => env(‘SFTP_PASSPHRASE’),
// By this
‘passphrase’ => env(‘SFTP_PASSPHRASE’),
]
Configuring stream options for SMTP is no longer viable. Instead, if supported, include specific relevant options directly within the configuration settings. For instance, to disable TLS peer verification, utilize the provided configuration example. Additionally, ‘auth_mode’ has been commented out as it’s no longer present in the latest version of Laravel.
‘smtp’ => [
// ‘auth_mode’ => null,
// Laravel 8.x…
‘stream’ => [
‘ssl’ => [
‘verify_peer’ => false,
],
],
// Laravel 9.x…
‘verify_peer’ => false,
]
Changes in Directory Structure
In recent versions of Laravel applications, the ‘resources/lang’ directory has been relocated to the project’s root directory under the folder named ‘lang’. If you’ve set a fixed directory for the language, it should be updated. It’s better to use app()->langPath() instead of depending on a hardcoded path.
Refactor your code
When transitioning to Laravel 10, it’s essential to handle any breaking changes and outdated features within the source code. Not every feature listed requires immediate code changes; modify them selectively according to how your project uses each feature.
Removed Functions
In Laravel 8, certain features were available but have been eliminated in the most recent version. You’ll need to find and fix these functions manually in your source code.
EnumeratesValues Trait: The function reduceWithKeys() has been removed. You might want to use the reduce() method in its place. Also, the method formerly known as reduceMany() is now called reduceSpread().
The method Illuminate\Database\Schema\Builder::registerCustomDoctrineType() has been removed. Instead, you can use the registerDoctrineType() method on the DB facade or register custom Doctrine types in the config/database.php configuration file.
Testing: Make sure to update every place where you’re using the assertDeleted() method in tests to instead use assertModelMissing().
Queue: The Bus::dispatchNow() and dispatch_now() methods are no longer available. Instead, your application should utilize Bus::dispatchSync() and dispatch_sync() methods, respectively.
The Redirect::home() method has been removed. Instead, guide your application to redirect by specifying a named route: utilize return Redirect::route(‘home’).
[Deprecated] – Blade – Lazy Collections & The $loop Variable:
@php
use App\Models\Car;
$cars = Car::cursor(); // cars lazy collection
foreach($cars as $c) {
echo $loop->iteration;
}
@endphp
In the example you provided, you’re attempting to use the $loop variable within a LazyCollection. However, this isn’t supported anymore. It’s important to note that the $loop variable still exists but it shouldn’t be used with LazyCollection. Doing so causes the entire collection to load into memory which goes against how LazyCollection is meant to function.
[Removed] – Storage
Storage – The cached-adapters feature is no longer supported by Flysystem. You’ll need to remove it using the composer command:
composer require league/flysystem-cached-adapter
[Removed] Get DB Expression String Value
In the prior iteration, you’d perform this action to obtain the Expression string:
$expression = DB::raw(‘select * from news’);
$expStr = (string)$expression;
However, that is no longer backed; instead:
$expStr = $expression->getValue(DB::connection()->getQueryGrammar());
[Removed] Eloquent Model’s $date Property
The outdated $dates property in the Eloquent model has been taken out.
protected $dates = [
‘deployed_at’
];
Please update your application to utilize the $casts property.
protected $casts = [
‘deployed_at’ => ‘datetime’,
];
[Removed] Testing – Service Mocking
The old MocksApplicationServices trait has been taken out of the framework. This trait is used to offer testing methods like expectsEvents(), expectsJobs() and expectsNotifications(). If your app relies on these methods, it’s suggested to switch to Event::fake, Bus::fake and Notification::fake instead.
[Changed] Validation – the ‘password’ Rule
The password rule now verifies that the provided input value matches the authenticated user’s current password and it’s been renamed to ‘current_password’.
[Changed] Blade – Avoid Overwriting Vue Snippet
Laravel 9 introduces fresh blade directives like @disabled, @checked and @selected which can conflict with your Vue directives. To avoid this, you’ll need to replace them with escaped versions @@disabled, @@checked, @@selected.
[Changed] – Collections
Now, with the latest update, you can pass a closure as the initial argument in Collection::when() or unless(). In previous versions, the first argument was strictly handled as a value and not executed. This new feature enables you to execute closures in that position.
$collection->when(function ($collection) {
// This closure is executed…
return false;
}, function ($collection) {
// Not executed since first closure returned “false”…
$collection->merge([1, 2, 3]);
});
[Changed] – Eloquent – Custom Cast With a Null Value
In Laravel 8, if the $value is set to null, the mutator set() method doesn’t run. However, in Laravel 9, it will be triggered. Because of this alteration, the outcome of the code snippet below will vary significantly:
// In App\Casts\FilenameWithTimestamp.php
public function set($model, $key, $value, $attributes) {
return time() . ‘_’ . $value;
}
// In App\Models\File.php
protected $casts = [
‘filename’ => FilenameWithTimestamp::class
];
// Somewhere in your program
// With Laravel 8, the result of the echo statement will be: null
// With Laravel 9, the result of the echo statement will be: “20230322_”
$file = File::first();
$file->filename = null;
echo $file->filename;
The filename being prefixed with a timestamp even when it’s set to null doesn’t make sense, as evident. In Laravel 9, it’s essential to address “the null case” for all your custom casts. For example:
// In App\Casts\FilenameWithTimestamp.php
public function set($model, $key, $value, $attributes) {
if (empty($value)) {
return ”;
}
return time() . ‘_’ . $value;
}
It is now functioning as expected.
[Changed] Storage – Throw Exception Behavior
In the past, Laravel would generate exceptions when encountering failed operations like attempting to read or delete non-existent files. However, in the latest version, Laravel now provides a suitable result directly like false, null or true instead of throwing exceptions.
This modification might affect your program if you’ve been relying on the try-catch block to manage failures. Consequently, you have two options: revert to the default behavior (as shown below) or refactor your code to explicitly check for failures (for example, using an if-else block).
‘public’ => [
‘driver’ => ‘local’,
// …
‘throw’ => true,
]
[Changed] Storage – Custom Filesystems
The process for registering custom filesystem drivers has been updated slightly. If you were creating your custom drivers or using packages with custom drivers, make sure to adjust your code and update your dependencies accordingly.
For example, in Laravel 8.x, you can register a custom filesystem driver like this, for instance:
use Illuminate\Support\Facades\Storage;
use League\Flysystem\Filesystem;
use Spatie\Dropbox\Client as DropboxClient;
use Spatie\FlysystemDropbox\DropboxAdapter;
Storage::extend(‘dropbox’, function ($app, $config) {
$client = new DropboxClient(
$config[‘authorization_token’]
);
return new Filesystem(new DropboxAdapter($client));
});
However, in Laravel 9.x, the callback given to the Storage::extend method should return an instance of Illuminate\Filesystem\FilesystemAdapter directly:
use Illuminate\Filesystem\FilesystemAdapter;
use Illuminate\Support\Facades\Storage;
use League\Flysystem\Filesystem;
use Spatie\Dropbox\Client as DropboxClient;
use Spatie\FlysystemDropbox\DropboxAdapter;
Storage::extend(‘dropbox’, function ($app, $config) {
$adapter = new DropboxAdapter(
new DropboxClient($config[‘authorization_token’])
);
return new FilesystemAdapter(
new Filesystem($adapter, $config),
$adapter,
$config
);
});
[Changed] Migrate from Swift Mailer to Symfony Mailer
In both Laravel 8 and its previous versions, the Swift Mailer library was the go-to for sending outgoing emails. However, due to its discontinuation, Laravel has shifted to Symfony Mailer. This change stands as one of the most significant transitions necessitating a refactoring of your code base as outlined below.
Updated: “Methods previously labeled as ‘Swift’ related to SwiftMailer have undergone renaming to align with Symfony Mailer equivalents. Utilize your IDE’s advanced search functionality to globally replace these methods with the provided list.”
Message::getSwiftMessage();
Message::getSymfonyMessage();
Mailable::withSwiftMessage($callback);
Mailable::withSymfonyMessage($callback);
MailMessage::withSwiftMessage($callback);
MailMessage::withSymfonyMessage($callback);
Mailer::getSwiftMailer();
Mailer::getSymfonyTransport();
Mailer::setSwiftMailer($swift);
Mailer::setSymfonyTransport(TransportInterface $transport);
MailManager::createTransport($config);
MailManager::createSymfonyTransport($config);
MessageSent Event Changes:
The Illuminate\Mail\Events\MessageSent event has been updated. Instead of using the type Swift_Message, it utilizes an instance of Symfony\Component\Mime\Email. This new instance holds information about the message before it’s sent. Additionally, a new property named ‘sent’ has been introduced. This property carries data about the message after it’s been sent, such as the MessageID.
Failed Recipients:
You can’t get a list of failed recipients after sending a message anymore. If a message fails to send, it will trigger a Symfony\Component\Mailer\Exception\TransportExceptionInterface exception.
FAQs
Can I upgrade from Laravel 8 to 10?
Yes, you can upgrade! Laravel provides official upgrade guides to make the transition smoother. However, it’s crucial to assess your project’s complexity and dependencies before diving in.
Is Laravel 10 stable?
Generally stable, but consider your needs. While released in February 2023, major releases often have minor teething issues. If your project requires absolute rock-solid stability, waiting for further patches might be wise.
Should I use Laravel 8 or 10?
New projects? Go for 10! You’ll benefit from the latest features and a longer support window. Upgrading from 8 to 10 is feasible, but weigh the effort against the gains.
What PHP version is needed for Laravel 10?
PHP 8.1 or higher is mandatory. This leverages newer PHP features for better performance and security. Ensure your hosting environment supports it.
Does Laravel have a future?
Bright and promising! Laravel has a large, active community and the team behind it is constantly innovating. They’ve shifted to yearly releases, ensuring stability and focus.
Is Laravel faster than pure PHP?
It depends. Laravel offers a structured framework, speeding up development and reducing common errors. However, for highly performance-critical applications, writing raw PHP might provide slight edge-case advantages.