Laravel 5 Fluent API: Dynamic Data Containers and the Fluent Data Type

4 min read

The "Illuminate\Support\Fluent" class is a useful data type. It allows for the construction of a data "container" similar to an array or instance of stdClass. However, the Fluent class makes it easier to make assumptions about the data the class instance contains. The following array and stdClass instance will be used for the next couple of examples:

1// Create a new array containing sample data
2$testArray = [
3 'first' => 'The first value',
4 'second' => 'The second value',
5 'third' => 'The third value'
6];
7 
8// Create a new stdClass instance containing sample data
9$testObject = new stdClass;
10$testObject->first = 'The first value';
11$testObject->second = 'The second value';
12$testObject->third = 'The third value';

We can access data from the $testArray like so:

1// Retrieve the 'first' item
2$value = $testArray['first'];

The $value variable would now contain the value The first value. Similarly, data can be retrieved from the stdClass instance using object operator (often called the "arrow"):

1// Retrieve the 'first' property
2$value = $testObject->first;

Like in the previous example, the $value variable would now contain the value The first value. There is nothing surprising going on here. However, what happens when a developer needs to make assumptions about the data their code is working with? Uncertain developers often litter code with unwieldy if statements and similar constructs. Failure to do so generally results in fatal errors.

For example, attempting to retrieve data from an array that does not exist results in an instance of ErrorException being thrown:

1// Will raise an exception
2$value = $testArray['does_not_exist'];

The exact error message will differ between single or multi-dimensional arrays, but the principal is the same. PHP does not like it when code attempts to access array elements that do not exist.

The same can be said for accessing an object's properties:

1// Will raise an exception
2$value = $testObject->doesNotExist;

The above code example will again throw an instance of ErrorException, with the error message being something similar to "Undefined property: stdClass::$doesNotExit". To work around this, the following code can be written:

1// Get a value from an array, or a default value
2// if it does not exist.
3 
4if (array_key_exists('does_not_exist', $testArray)) {
5 $value = $testArray['does_not_exist'];
6} else {
7 $value = 'Some default value';
8}
9 
10 
11// Get a value from an object, or a default value
12// if it does not exist.
13 
14if (property_exists('doesNotExist', $testObject)) {
15 $objectValue = $testObject->doesNotExist;
16} else {
17 $objectValue = 'Some default value';
18}

The above code example can be simplified using Laravel's array and object helper functions. Specifically see the sections on array_get, object_get and data_get.

In the above code example, we checked to see if an object instance has a value by using the property_exists function instead of the isset function. This is because the property_exist function will return true if the property exists and has a value of null. The isset function will return false if the property exists but has a value of null.

Developers need to assume things about code quite often. In a perfect world, developers would know exactly what data an array or object their code interacts with contains. However, when dealing with remote data, such as data from external APIs, or when interfacing with code from multiple development teams, this is not always possible. The Fluent class can be used to simplify things for developers.

The following example will create a new Fluent instance with some data:

1// Some example data, which could be obtained from
2// any number of sources.
3$testArray = [
4 'first' => 'The first value',
5 'second' => 'The second value',
6 'third' => 'The third value'
7];
8 
9// Create a new Fluent instance.
10$fluent = new Fluent($testArray);

Now that we have a Fluent instance, data can be retrieved just like an object or an array:

1// Accessing a value like an array.
2$value = $fluent['first'];
3 
4// Accessing a value like an object.
5$secondValue = $fluent->first;

Both $value and $secondValue would contain the value The first value. Accessing data that does not exist now simply returns null, without raising an error:

1$value = $fluent['does_not_exist'];
2 
3$secondValue = $fluent->doesNotExist;

Both $value and $secondValue would contain the value null. The Fluent class does expose public methods in its API to custom the default value returned.

Thanks for taking the time to read this post! If you found this article useful and want to help support more work like this, please consider sponsoring my work on GitHub, or by checking out some merch.

 Sponsor on GitHub  Shop Merch