Buy

Private Constants

Okay enough with type hints and return types! PHP 7.1 added another cool feature for class constants: we can finally make them private!

In GenusController find, getNotesAction(). This is used by an AJAX call to load notes that appear at the bottom of the genus show page. For example, go to /genus and click on one of them. Bam! At the bottom, an AJAX call loads a list of notes, complete with an avatar. That comes from the avatarUri field that's returned.

Look at the /images/ part: that looks funny to me. All of our images are stored in that directory, and that's fine. But I hate having random strings like this in my code. This is a perfect place to use... drum roll... a constant!

Open GenusNote, which is the object we're rendering on this page. Add a new constant: const AVATAR_FILE_PREFIX = '/images';. Then, in the controller, use this: GenusNote::AVATAR_FILE_PREFIX.

103 lines src/AppBundle/Entity/GenusNote.php
<?php
... line 2
namespace AppBundle\Entity;
... lines 4 - 10
class GenusNote
{
const AVATAR_FILE_PREFIX = '/images';
... lines 14 - 101
}

160 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 15
class GenusController extends Controller
{
... lines 18 - 118
public function getNotesAction(Genus $genus)
{
... lines 121 - 122
foreach ($genus->getNotes() as $note) {
$notes[] = [
... lines 125 - 126
'avatarUri' => GenusNote::AVATAR_FILE_PREFIX.'/'.$note->getUserAvatarFilename(),
... lines 128 - 129
];
}
... lines 132 - 137
}
... lines 139 - 158
}

So far, this is all stuff we've seen before. And when we refresh... yep! Everything still loads.

Private Constants

This is an improvement... but it would be even better if I could call a method on GenusNote to get the complete avatarUri string, instead of calculating it here in my controller. In other words, I don't want anyone to use our constant anymore: we're going to add a public method instead.

In PHP 7.1, we can say private const.

103 lines src/AppBundle/Entity/GenusNote.php
... lines 1 - 10
class GenusNote
{
private const AVATAR_FILE_PREFIX = '/images';
... lines 14 - 101
}

Now, accessing that constant from outside this class is illegal! That means, if we refresh, our AJAX calls are failing! On the web debug toolbar, yep! You can see the 500 errors! If I open the profiler and click "Exception", we see

Cannot access private const from the controller

Awesome! So now that I can't use the constant anymore, I'll be looking for a public function to use instead. In GenusNote, add a public function getUserAvatarUri(). Hey! We're PHP 7 pros now, so add a string return type.

116 lines src/AppBundle/Entity/GenusNote.php
... lines 1 - 10
class GenusNote
{
... lines 13 - 64
public function getUserAvatarUri(): string
{
... lines 67 - 73
}
... lines 75 - 114
}

Before we add the logic, let's make things fancier. Suppose that sometimes there is not a userAvatarFilename value for a note. If that's true, let's show a default avatar image.

Back at the top, add another private const BLANK_AVATAR_FILENAME = 'blank.jpg'. We'll pretend that we have a blank.jpg file that should be used when there's no avatar.

116 lines src/AppBundle/Entity/GenusNote.php
... lines 1 - 10
class GenusNote
{
... lines 13 - 14
private const BLANK_AVATAR_FILENAME = 'blank.jpg';
... lines 16 - 114
}

Back in the new method, add $filename = $this->getUserAvatarFilename();. And, if (!$filename), then $filename = self::BLANK_AVATAR_FILENAME... because we can access the private constant from inside the class. Finish the method with return self::AVATAR_FILE_PREFIX.'/'.$filename;.

116 lines src/AppBundle/Entity/GenusNote.php
... lines 1 - 10
class GenusNote
{
... lines 13 - 64
public function getUserAvatarUri(): string
{
$filename = $this->getUserAvatarFilename();
if (!$filename) {
$filename = self::BLANK_AVATAR_FILENAME;
}
return self::AVATAR_FILE_PREFIX.'/'.$filename;
}
... lines 75 - 114
}

Nice! Back in the controller, we're still accessing the private constant, which is super obvious. That'll push me to use the public function getUserAvatarUri().

160 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 15
class GenusController extends Controller
{
... lines 18 - 118
public function getNotesAction(Genus $genus)
{
... lines 121 - 122
foreach ($genus->getNotes() as $note) {
$notes[] = [
... lines 125 - 126
'avatarUri' => $note->getUserAvatarUri(),
... lines 128 - 129
];
}
... lines 132 - 137
}
... lines 139 - 158
}

Refresh one more time! Love it!

Leave a comment!