You might think you know PHP, but if you dig below the surface you might find it can do more than you knew. Beyond the documented features, there lies a world of tricks, hacks and other techniques that can allow PHP to go a step further.
In this talk we’ll look outside the box at some things PHP provides like references, autoloading and magic methods and explore how using them in an unconventional way can benefit our own code.
Video Transcript :
Hi if you don't know me i'm liam hammett i
do a lot of stuff with php particularly around the laravel ecosystem and today i'm going to be talking to you
about unconventional php um we'll be going over some of the ways that you can use php in a way that you
probably haven't thought of before if you're a beginner with php it might be a little bit hard to follow along
with some of the things but i'll try to explain everything as clearly as i can if you've got any questions then
please ask them in the chat as we go along and i'll try and clear them up at the end if you've worked with php for any amount
of time you'll probably know that it has a lot of ways that let you interact with php source code itself so pitchfield
gives you ways that you can sort of reflect on classes and values and you can pass tokens of source code you can evaluate
new source code on the fly you can serialize objects and you can do so much more
and i expect a lot of you watching this to sort of have this gut wrenching reaction to some of the things we're going to go
over and think they're horrific you won't be seeing most of these techniques that we're going to go over
in the php documentation or in any of those well-known books about design patterns or following solid
principles but that doesn't mean that these tricks can't be useful and i'm not going to go and tell you to
immediately go and use all of these in production code either but i would kind of want to have this talk to make people aware that there are
options to write php code in sort of new interesting ways
we're going to be going over a couple of things where we can bring functionality that's already used in production frameworks like laravel
we'll be seeing how to make the most out of some of the other technologies that we've already got and how we can add to them
and we're going to have a little look at how we can enable certain functionalities that other languages support but php doesn't yet
but before we look at what future features we can find i kind of want to stop and reflect on the past to quickly talk
about what initially prompted me to give this talk so that we can see how techniques like
the ones we're going to go over today have been useful in the past and therefore why they're still worth
discussing so a few months ago i was trying to find some documentation
on php.net and i came across this page about type hinting and the page was pretty empty so the
user contributed comments so jump to the top of the page and i started reading the first one
and it was explaining how to be able to type in your function arguments with primitive types like denoting that this
argument must be a string or that one must be an integer and that might not sound very interesting but
what jumped out about this to me was that this comment was from 12 years ago it was from 2008 and at the time php 5.2
was the latest version and if you've not used php for that long you might not be aware but
you couldn't actually type in perimeter values like this until seven years later when php7 came
out in 2015 and so this kind of blew my mind because
someone managed to build this highly wanted feature that will run in any php environment
seven years before the language itself supported it and even better than that it turned out that it was the exact same
api that we got in php7 so upgrading a project using this technique
was completely effortless so i want to quickly see what the problem is and show you and see how they solved it
so here we've got a simple function that checks if a string is a palindrome so if it says the same reading backwards as it
does forwards as you can see this kid's being executed against php 5.2
and we've type into the value as a string which like we said wasn't actually possible in php 5.2 so
when we try to call the function we get an error and there is a bit confusing it says
argument 1 pass 2 is palindrome must be an instance of string string given
that's because string wasn't actually a reserved type so it was expecting us to get a class with the name string but we gave it a
literal string so let's now have a look at how this post from 2008 on php.net actually
managed to make this work and here's a slight variant of the code that they wrote to get this working that
i just wanted to quickly look at the main thing that it does is that it sets an error handler
so whenever php encounters an error it will run this function to do some custom logic
so there's a lot of stuff here but we're just going to go over the important bits
one of the first things that it does is it checks the error message that came up from the error and make sure it
matches a certain pattern so we're matching it against the pattern that we just saw so
argument a must be uh argument a pass to b must be an instance of c and so this way
we know that we're dealing with the right error once it's done that it goes on to use this debug backtrace function
which is a special utility that php provides and what it will do is return a list of
all the functions that were called to get to this point in time and along with any extra little details like what values were passed into those
functions so now we have that debug backtrace and it passes it into another thing
that we'll go over and basically iterate over every function that was called until we find the one that triggered the
error and when we do that we actually also pull out the value of the argument which we can
then use to assert against so once we've got that we've got we know
what type we're wanting to hint against we know what the value is and we know that we're dealing with the right error
so we really have to do is check that so here we've got a little mapping that gets called
so in our palindrome example we type into the value of the string which maps to
the is string function which is something that php already provides
so if we've passed it through a string and we're checking the string function it will sort of return
true and returning true from an error handler sort of tells php okay pretend like this error didn't
happen and just continue running the code like you were before
and if none of those conditions were met maybe uh it wasn't actually string that we
would that we were passing through or maybe when dealing with a different error then it will return false and that
tells php stop and continue executing the code like you were before that's kind of it now the only change we
need to make to the initial code that we had was to make sure that we include this error handler and it suddenly works
and with only like a few lines of code that now we understand we could use this
nice syntax to check if a value is a string all the way back in php 5.2
now that might not seem particularly relevant today hopefully everyone watching is running recent versions of php already
but the idea of that is to show you that php isn't just a closed box of documented things that you're allowed to
do if you think a bit more abstractly you could make it do a lot more and here we managed to introduce a clean
native feeling syntax into php seven years before php got it itself
so so step back and think what will php like what will php be like seven years from
now in 2027 what features from then would you like to have but you don't have to wait
nearly a decade for it and that's basically the premise of this talk today
so the first one i want to talk about is typed variables and this is something that nikita one of
the primary maintainers of php talked about when php74 was first released
and that's because it's only now possible with the new features it introduced but when you heard about php 74 coming
out you probably didn't hear about typed variables and that's because it's not really a first party feature
it's something that we can kind of make work so let's say we have a variable i but we
can't be sure what type it is it might start off as an integer but it can be reassigned to something else later on so in a nutshell typed
variables is a way to prevent that and make sure that the variable doesn't change its type later on in the program and we
might start protecting something like this by wrapping it in a function and this way we can ensure that the
initial value is always an integer but it still doesn't check for it being reassigned later
so unless we call this function every single time we change the variable it won't get type checked so see how we
can make this function actually do what we want it to we've rewrote a little bit here
so that it basically does the same thing we're creating a class with a type
property called prop we're assigning the integer to that property and then we're returning the property
and on its own this has no different effect in the previous code and that's because we're just returning the value
of the property at the time but the interesting thing is if we tried to change the value of that property
php would throw a type error because it can only be an integer and it can't be a string
so we need to do a little bit more to get that working and the first thing is to add uh is to add these ampersands to
uh both the assignment and the function and that will tell php that instead of returning the real value of the property
we just want to return a reference to it we want to return a reference to the property on that class
and that's important because it means that now when we reassign it it's treating it as if it should be
reassigning the property on the class 2 and it will validate the type as we do that and
that wouldn't happen with regular argument and return type pins and functions unless you pass it through to the
function every time so there's only one last little caveat that we have to worry about here which
is peach piece garbage collection and this is what php does to try and free up memory by getting rid of
things that we no longer need in this function when we return php
thinks that we no longer need the object at this point and we only need the property value
so it'll completely get rid of the object meaning that we're not dealing with the types properly anymore
and somehow we need to keep the object alive so that it is a real object and property even after
we've returned from the function and one kind of simple way to do this is just by adding it to
a superglobal variable and that means that the object will always be referenced in memory
even after the function's returned to value and this means that php doesn't destruct
the object so we're attending a real reference to that property which still has the type against it and magically now that works
now when we reassign the variable to a string later on php will try assigning it to the type property
and it will throw that type error and just to show this works we can still reassign the variable to something else
later on as many times as we want but as soon as it becomes a different type it'll throw an error that you can handle
and this approach may seem a little hacky but it now lets us protect variable types in our code in a way that we just
previously couldn't in php and this can have huge benefits for long procedural code
i'm just going to have the super water
so the next trick we're going to go over is called function piping which is
something else that can help with a lot of procedural code problems what do i mean by piping you might be
familiar with the term if you've used a language like bash where it's a commonly used feature but
simply put means taking one value and piping it into another function so to start off let's see what problem
this solves we've probably all seen code like this at one point in our careers
it's a single line that does a mishmash of things and it's really hard to read here it doesn't even fit on the screen
so let's split it out to make it easier to see what's going on so essentially this code is just getting
the event id from the given url but it's so hard to read and understand that
what i hate about this the most is that it just doesn't read very naturally you gotta start off in the middle to
figure out what the initial value is and then use that in the context to read a bit further out to see what that does
and then again and again so you get the whole context of what the final value is
so we could rewrite that code into something like this which gives us the advantage that now we can see what the initial value is
and we can read it from top to bottom until we get the final value but i think this still isn't very nice
it's better but it's not clear and you probably don't have to spend time coming up with a name for every
step along the way after all naming is one of the hardest things in programming
so incomes the pipe operator rfc which was proposed by sarah goldman a
few years ago the idea of this rfc was to introduce a
new syntax to help make code like this easier to read and so this is what the new syntax would
help make our same code look like and i think this is a lot cleaner personally and you can read it from top to bottom
without having to worry about the intermediary steps it introduced this new dollar dollar
symbol and that represents the last value from the function so that you can sort of decide which
which position in the function arguments you want to pass it to but unfortunately this rfc didn't pass
so this code doesn't work for now however with a bit of effort we can
actually get this very similar syntax working ourselves today in php it's so
similar i don't know if you even were able to spot what the difference is so just like before we want to
pipe a value through some functions and get the result so how do we make
that work well we started off with the pipe function where we passed in the initial value
so we'll have a pipe function and this is going to return another object
the object isn't very special to start off it takes in the value and saves it as a property that we can reuse later on
but the real magic happens inside this magic call function and this is a special function that php
provides that makes things behave in a bit of a special way essentially whenever a
method on this object is called and that method doesn't exist on this class this underscore underscore call function is
going to be executed instead and that lets us do our own custom logic instead of php just throwing an error to
say this method doesn't exist so firstly it checks if any of the arguments passed at the function
match that special dollar dollar syntax and if so then we replace that dollar dollar with the real value that we got
then it moves on to this cool user func expression and this basically passes through the
method name that we got and executes a real php function with
them so for example when we try to call arrow pass url
then that would come through here and php would execute the real core pass url function with the
arguments that we gave it and then the final thing the cool match the magic call method does
is it returns the new value um but again in another pipe and that means that we can chain as many
of these cool methods off of it as we want but when we do want to stop that chain we have this get method where we can
just return to real value and stop stop the piping
so cool now we know exactly how this code works and it's only really a few lines long behind the scenes the pipe function returns an
object so that we can call methods off of it when we call methods it just so happens that we're using real php function names
but they're going through our custom cool function and when we want to stop the chain and get the real value we can
just use the get function now there are obviously some downsides to an approach like this one of which
is that because it's treating them as class methods instead of functions you could lose ide support it wouldn't
know how to tell you what the arguments for these methods are because the methods don't really exist
however this might be an approach that can help you clear up lots of ugly long procedural code that you have around
like this example
the next trick that i want to go over is static constructors and these are a concept that a lot of
different object oriented languages have but unfortunately php doesn't really have first party support for them
so if you're not familiar with the concept a static constructor is just a function you can add to a class and that can be
used to initialize any static properties or to perform any actions that only need to be done once for that class
let's start off and just have a little look at what problems static constructors could help solve
here we've got a simple class that can get us a list of countries by reading them from a json file it's
pretty straightforward but it has one problem every time we want to get the list of countries it's going to read and decode that json
which can be a pretty slow operation especially if we do it a lot so instead
we might use a technique called memorization so that we only read the file once now with this updated code it'll only
read the file once and it will save the results to the property and that means that we can call this function as many times as we want and it
will have the same result without opening that file again and again and this approach forces us to go
through a getter instead of accessing the property directly because we don't know if the property actually has values
this is a pretty common pattern in php but sometimes we might actually want to interact with the property
so let's take a look at what this might look like if we do it with static constructors but just before we do that let's
understand exactly what a static constructor is and what rules it needs to follow so a
static constructor is a static function that belongs to a class and it should take no parameters because you
should never really be calling it manually in your application it should only be called once we don't
have to call it several times over it should be executed before any
instances of the class are created before any static properties are referenced and before any other static
methods are called so really it's just a simple function
with nothing special about it all we need to do is make sure that it gets called once before any of the things in the class
gets used so let's set one up here we've got a
function called underscore underscore construct static and this is just to follow the naming convention of php's regular magic
methods but there's nothing really magic about this one yet it just loads the same file into the property just like we did before
so how do we make sure this function actually gets cooled before we try and access any values or do anything with it
it must be hard to build something that meets all those rules right well what we really have to do is call
it in the same file that the class has defined and that's kind of it this means as soon as we try to reference the countries class
somewhere this file will get autoloaded which means it'll first define the class
and then it'll execute this function immediately before you can do anything with it and this is such
a simple and straightforward pattern but it can give you a whole new way to hook into classes and do some kind of logic
of your own and it's not just limited to initializing properties either you can
do whatever you want in this function so let's take this example of a
controller in a laravel application the gist of a controller is that you hit a specific url in your application
and it'll figure out what controller needs to be used for that url and then it might return something like
an html page or an api response but we don't really care about what the controller does in this case
but how do we know what url should map to this controller
typically in laravel and in most other frameworks you will have your roots defined somewhere in a file
or an array that sort of maps the url to the controller that it should use and this can be kind of nice because it
gives you one file that you can use to figure out where any request hitting your application starts off
but we could also use static constructors for this so by defining the route in a static
constructor instead now this root definition is part of the class it sort of belongs to it's all in
one file and grouped together so you don't have to figure out how different parts of the application
come together and where those bits belong and this is just one example of how we
might use it but there are plenty more possibilities that different applications might be able to make use of
but remembering to call this construct static function at the end can be can be a bit of a hassle though so what
if we could make it so we don't need to put that in every file income custom auto loaders and this is
hands down one of my favorite ways to make php do interesting things if you're not familiar with what an auto
loader i'm going to quickly recap if you try to use a class in php it
might not be aware of what that class is because it's not loaded those files in yet so it'll throw an error so php provides
this handy spl auto load register function and that lets you hook into this event so that
when php doesn't know what a class is you can do some custom logic to try and load that class in
here we've got the simplest possible auto loader where if we try to load a user class it'll try
and load the user.php file which should define what that class is
autoloading can get quite complicated though if you're loading things from lots of different directories and using namespaces
maybe including third party packages the auto loading code would be an awful lot more complicated than this
so the php tool built uh php community built a tool to do this for us
and odds are if you've only been writing php within the last seven or eight years you've only ever used composers to do
this stuff for you and you might not have even been aware that you could write your own custom auto loaders
and composer in its autoloader is great so when i talk about custom autoloaders i don't mean that we should replace it
with something else instead what i mean is that you can have more than one or two loader active at a time so you can do extra stuff on top of
what composer does or even before composer's done its own work
and autoloaders are typically meant to load files automatically it's kind of in the name but they don't really have to
do that they can do whatever you want so let's write one that will automatically call our construct static
function for us so here we're requiring composer's own
autoloader then we define our own custom one that will run after composers done
since composer already loaded the file at this point we can just check that the class already exists and has been
autoloaded but we want to make sure that we pass through the autoload false flag so that we don't accidentally get into a
recursive loop and try to autoload a class that we already know doesn't exist
and then if that happens we can just check if the loaded class has a construct static method on it
and if it does we can just call it now we don't need to include that line at the end of all our classes
you just use a static constructor and i want to add a bit of a disclaimer
that it's not actually quite this simple to add an autoloader into the chain to run
after composer there's actually a little bit more logic you've got to do to hook into when composer has autoloaded a file but
it's absolutely possible and i can share a link to a plugin that does that already if someone wants after the talk but the
theory is basically exactly the same as this example shows
so keeping on theme with static constructors i want to quickly look at how we can use them to
enrich our applications with a new feature of php8 and that is attributes particularly
class attributes so let's go back to this example of a controller and
remember that it needs a root defined somewhere that maps the url back to the controller
instead of using a static constructor like we did before let's take another approach to it and
see how this might be looking if we use an attribute
so here we've got exactly the same control as before but where's one notable difference
now we're defining a custom attribute on the class and that defines what the url should be
if you're not familiar with attributes they're essentially meant to be a replacement for most doc block comments
but because they're not just comments they're actually a first party feature in phpa and that means that they can get a lot
more powerful they can actually map to a real class and that class can contain logic
so let's look at what that class might look like it's a pretty straightforward class to
start off all it's doing is accepting the message the method and the route that we gave it and saving those
as properties for us to use later the thing that stands out here is that there's actually an attribute called
attribute defined on the class which turns this root class into an attribute so let's see how we
can make use of this new one that we've defined again we've got an autoloader function
and this will trigger whenever we reference the class so in this case we care about when the controller is being referenced somewhere
so using the reflection class object we can actually inspect what the controller is and get
some information about it such as what attributes has got and from then on we can it iterate over
all of the attributes that it's got and find when we have the root attribute that we defined
and when we have that we can just call this attribute new instance method and this will create a new instance of that
root class for us and interestingly this will actually have it with the parameters that we gave it when we added
the attribute to the top of our controller so now that we're loading the custom
attribute and it has the parameters we want to use let's make it do something we're going
to add a new register method to the root class and this will do all the work that we want really
this new function is going to accept the controller's class name and then we're going to use it to register a root exactly like we did before in the static
constructor now in our auto loader all we have to do is call that register method and give it the controller's name that we're loading
and we're done so with just a few lines of code in an autoloader and making a
custom attribute we've kind of introduced a whole new way that you can set up routing for your application that might appeal to you
your root in the controller can be kept in the same file and again this isn't the only thing that
attributes could be used for you could do whatever logic makes sense for your application or class
you might use this approach to apply a middleware to a controller and an orm like doctrine or eloquent
might use it to define what database columns belong to a model and i'm sure we'll be seeing many more
interesting uses of them as adoption of phpa rises as it gets released in a few months
custom auto loaders can do quite a lot more though and i think hands down my favorite one is
real time classes and this is a super interesting way to use an autoloader to
make some magic happen and essentially what i mean by a real-time class is that you can just create a new
class file kind of on the fly in real time even before composers try to load it in
and maybe even more interestingly than this laravel has this as a first party feature called
real-time facades and it's got quite a lot of use and adoption over the laravel community
um so to rebuild real-time facades let's quickly look at what a regular facade is and how it can be useful um so we're
going to start off with a pretty basic class to send an email it lets us set who the email is going to what the
subject line should be and what the body of the email is and then when we're done we've got a method to
send it so when we use this class we firstly need to make a new instance
of it and then we can call the methods off of that in whatever order we want
so the thing that facades will do is they'll get rid of that step where we need to make a new instance of the class and it does this by making all
of the methods on the class available as if they were also static methods
so we can take this and basically get rid of this first line
the facade class itself might look like this it's a completely separate class and
it just defines a cool static method and just like the magic call method before
this is kind of special and whenever we try to call a static function that doesn't exist on the side class
it'll call this instead and pass through the parameters that we have and so this cool selling method is just
doing exactly the same as we did before it's making a new email object and then calling the same method of that
instance so it's pretty simple really and when we
try to use it we get this new interface where we don't have to create an instance of the email class we can just call any of
those methods as if they were static to begin with and then change things off of that and
laravel's own facades does a bit of extra magic behind the scenes so it does stuff to automatically do
dependency injection and to make the facade classes mockable so that they're easy to test
but the simplified version is good enough for our use case we don't really want to have to create a
new facade class every single time you want to use this functionality though so how can an auto loader help
so again the spl autoloader register function actually has a couple of extra parameters that we can give it and notably it gives
us the option to prepend our autoload function to the start of the autoloading stack
so if we set that to true normally that means that our own autoload function would get called before composers done its stuff
so we can override the default behavior to find the class and by the way this prepend colon
syntax is actually valid in php 8 with named arguments
um so what if we want to use this to write a facade class on the fly in real
um time going to add a bit of logic to our autoload function and we're going to have a convention here so that if we try to
load any class whose namespace starts with facades we're going to assume it's a real-time
facade and run our custom logic we're also going to make a new facade directory to put these
files in at this given path and we're going to make sure to hash the class name to jaw1 just to deal with any special
characters that might be in it so now that we know what path we're
going to put the file in the first thing we can do is check if it already exists if it does we can just load it and
return true to stop trying to autoload but if it doesn't exist we still need to
make it so the first thing we'll do is make sure that the facades directory exists and then we'll touch um we'll touch the
file path just to create an empty file and now we need to populate that file with something
so to prepare for that we actually need to figure out what the real class name should be by stripping the facade bit from the
start of the class name and that's because we need to actually use it in the file that we're going to write
and after that to write the actual php class to the file we just need to literally put the code there we can have
the raw code as a completely plain string and we have the real class name into
that so that the final file has has the right class name and can create an instance of the correct class
and then we just send it through the file put contents function into the empty file that we just made
and the last step that we need to do to get that working is require the newly created file to
load the class and then return true to stop php moving on to compose zone autoloader
and that's kind of it now we've managed to make this autoloader that will generate brand new files on the fly when we
demand them and now that we're done this is how our final clip might look like
so long as we have uh autoloader running then we can prefix our email
classes namespace with facades even if that facade email namespace doesn't exist yet
and we can call any of the functions off it statically even if they're not static methods on the real email class
and here we can see what our folder structure might look like after our auto load is run where the
facades directory contains a file aimed with a show one hash that we gave it
and now this will work with any class whatever uh whatsoever anywhere in your
code base so long as we import it from that facade's namespace and so you're probably wondering isn't
this going to slow down a code base a lot if it's got to create new files all the time and the answer to that is that it only
really has to make the file once and then it's saved and it can also load like normal
and it'll only do it for each facade class that you try to use in your own code base it won't do it all the time
for every single class that you have in your code and as soon as this
file's be been created it can also be loaded into op cache and has
full performance benefits just like any other normal class does and they don't really have to clutter
your get repository either because they can be made completely on the fly you can get ignore that
facade's directory and it will just generate them when it needs to that first time
and now again this is just a small convenience in this example but you can use this technique to create
any classes you might want on the fly or even add more functionality to the facades here
but now let's take custom autoloaders and real-time classes to the extreme and let's talk about pre-processing
you're probably familiar with front-end pre-processing with tools like sas and less that
compile a similar syntax down into plain css and there's also bible which lets you
take your javascript and automatically rewrite it so that javascript works in any browser
but what you might not know is that we can do that exact same thing with php on the back end
so there's this tool from christopher pitt and it's called pre and i think the tagline speaks for
itself it gives you syntax you like that runs where you need and essentially
this is a composer package that you can just install into a project and it makes use of a custom autoloader
and it'll pre-process your source code as it gets loaded so that you can write php with
pre-custom syntax on top and this package will rewrite it into a file as plain php so that it can
get run by the php interpreter and it's kind of exactly like how real-time classes work before
but this is to a much more extreme level and bree's already supported a lot of
the things in the past that we've eventually managed to get into the php core like allowing trailing commerce and a
list of function arguments and being able to use short closures but it can still do so many things and
unlock so many new ways to write code that we just can't do in php today and i've
got a quick couple of examples i want to quickly go over so one thing that it can let you do is
set dynamic values in your properties directly so if you want the default value of a property to be the result of
a function call or maybe an instance of a new object you can't normally do that in php but
pre can do it for you and unless you do the same thing with
function arguments as well there's also a pre plugin that allows
you to write html literally inside your php code just like we can do with
react and javascript and jsx
we can make operations asynchronous with the async await keywords just like we used to in javascript
instead of plain arrays you can create collections that are array like lists but have a lot of extra
useful functionality built in you can even defer bits of code to be
executed at the end of a block so for example we can open a file and
immediately defer that file to be closed and that doesn't mean it will immediately close the file but it'll do
it at the end of the block which lets you keep the closing logic close to the open stuff instead of having 50 lines of other unrelated code
in between and like i said before i don't think we're actually allowed to have a php
southwest event without mentioning this for dave because he absolutely loves generics
where you can add a type into a class and that type can actually be different depending on how you instantiate the
class and as you can see these are a lot of features that i'm sure we'd all love to
have in php today and tools like pre actually make it possible to use but even this is still just
sort of scratching the surface we can still do all of these things in php but just
a lot more verbosely than pre allows us to do so for something more powerful that we
can't do in user land we can turn to extensions
and a lot of people think that extinctions only introduce new classes they see things like the
redis extension and the dom document extension and all they really give you is a new
class that you can interact with but extensions can actually do a lot more to php
they can introduce new syntax new core functionality and they can just unlock things you've
probably never even thought of the first one i feel obliged to mention
is called swool and this is an extension that can basically replace php fpm in your web
server stack and doing that gives php native async await functionality you can also
run code in code routines you can manage your php processes with it you can
host web server sockets websocket servers with php and even just using it significantly
improves the performance of a php application out of the box even if you don't use any of its other features
so if you're if you're serious about writing php apps that are more than just a typical web app i think
you should definitely check that out uh the next extension i wanted to mention is one by
nikita popov and this offers a different way to interact with scalar values like strings and integers
and unless you treat them like objects so this extension gives you a new
function where you can register a primitive type handler and you can do this by giving it the
type that you want such as a string and pointing it at a class where you want that class to be the object that
gets dealt with that string so now if we have an instance of a string
we can call these methods directly off of it as if they were an object to begin with
and i think this is a super interesting idea personally because you can essentially use this to define
your own way to interact with php completely maybe you don't like naming inconsistencies in some of php's core
functions i know i don't and maybe you can't remember if needles or haystacks come first
so you can actually use this to define your own version here without having to affect how php's
functions currently work and without breaking any backwards compatibility
the last extension i want to mention is another php core contributor sarah gilman and
it's called operator overloading but what is it uh php has a wide range of operators that
you can use to compare two values to one another or to add them together or to concatenate strings
or so on but typically we only really think about using these with the primitive types like integers and
strings but operator overloading is a feature in a lot of other
object-oriented languages that actually lets you run custom logic when you use an operator on
one of your own classes which can actually make it feel a lot more natural to use and you might
not be aware but php already does this internally in a few of its own classes
for example if you want to compare two date time objects together php will realize that if you're using
the greater than or less than operators you probably want to know if one date came before or after the other
and this makes it really easy to write and read this code so the operator overloading extension
brings this kind of functionality to our own classes in php
so we'll take this example quickly where it might come in handy we have a class that represents how much
money something is but it can support multiple different currencies so if we try to add two money objects
together it would just throw an error normally in php but with this extension enabled it'll actually
call this magic add method and that lets us do what we want to figure out how to add the values
together so for the example of money we might want to convert the value from one
currency into another and that lets us add the two values together
but the thing about operator overloading is it's not just limited to numeric values either you could do whatever
logic you want here so long as it makes sense you might use the additional operator to combine two collections into one
or maybe you want to replicate bash's double angle bracket syntax so that you can pipe a string into a
file object and there are a couple of extensions
that we can use today but what other opportunities can we look forward to in the future php8 is just around the corner it's
being released in november 2020 and there's already betas available to use
and it brings a lot of nice new features but it also brings a couple that we can use in these unconventional ways
the first one to mention is weak maps and weak references and these let us reference objects
without interfering with garbage collection and this brings forward a great way that we can
share objects around multiple parts of the code base but without keeping them in memory and sacrificing performance if
they're not needed and this just isn't something that we could reliably do before so we had to resort to other patterns
another one that we've already explored is attributes um we've explored one use case but
there's plenty more out there attributes are present in java in javascript in python
and so many other languages and they've already got a lot of different uses across all of those and now we can bring them to php and
like i said before dark blocks did some of the works attributes could but now attributes can do so much more
because they can have a real code attached to them and they can even go in more places than dot blocks could
and that's kind of all i have for you today hopefully it's made you think a bit about how powerful php can
be as a language and how you might be able to get some future like syntax and
tools that can help you improve your own applications and i want to clarify that i'm completely
aware that everything we've covered here is a little bit weird and if you're looking
at it for the first time or you've got a team member looking at you implementing this for the first time
it might not be obvious what they're doing so these techniques may not be suitable for every scenario and even if you don't use
these techniques directly hopefully in the process you've learned a bit about autoloaders magic methods references and
some other things that php provides that you can work into your own applications maybe in a more conventional way
um yeah that's it feel free to follow me on twitter or check out my site where i occasionally talk about doing wacky
stuff with php there's a link to the slides at the bottom there but i'll make sure to tweet our link to them later too
if you've got any feedback for either myself or naomi please leave it on joined in and thanks to php southwest for having
me wow thank you very much for that that's
that was really interesting that was a i've got so many questions um but if
anyone else has got questions uh please can you add them to the the q a um
i had one question i think i was just probably missing something in your root example um when would the roots get auto loaded
that is the one thing that i didn't actually mention um if i can find it again do you have to
work out what all the yeah i couldn't really work that out so uh which one was it i guess in either of
the examples with the attributes or the static autoloader yeah somehow load that class in first
and loading a class is actually kind of an inexpensive thing you can do in php so you can iterate over a directory and
just load everything in it i see so you've had a convention your controllers in one place you just
iterate through all of them more yeah okay
cool thank you um right question from dan uh why do you
think a precur why do you think a pre-compiled step is so standard in javascript well but so
rare in php is there anything we can do to make pre-compiling more common
i think it was needed in javascript for a long time because um you don't know what environment your
code is going to run in if it's going to run in an old version of javascript from 20 years ago in like ie4 that someone's
using somewhere because someone probably is but in php we've got control of the server so we always
know what it's going to run in so if we want a new new if we want to use new syntax in php we just
upgrade php but we can't really do that with the user's browser
so that's why i think it's common in javascript but not so well known in server-side languages cool thank you
dan if you want to come back on anything then just add an extra message in there david lum asks uh what
tool uh did you use the line highlights highlighting in the presentation it was really good
um i've got these on slides.com which offers it but there's an open source uh
thing called reveal js which basically lets you make slideshows like this and
that's one of the features of the codeblocks oh wow brilliant um i was a bit afraid of doing um
live coding for all this stuff so i figured this is a pretty good alternative to point at what code i'm talking about
yeah no i like it i like it uh there was that can you can you tweet that out please uh what the tool you use or put it in
the uh yeah sure the channel yeah thanks um
i mean no one else has got any questions oh no there's one more um uh dan asks is there anything we can do
to make pre-compiling more common um i think it's a tough one because
pre-compiling is a it's a really awkward thing because if you if you've got files that don't
have normal php syntax like that then suddenly tools like
some or php cs fixer will see it and they'll go that's an invalid php file i can't do anything with that
so it's kind of this trade-off where if you have non-standard php files with pre-processing you
can't necessarily use all the tooling that php currently has available
so um there's actually a project by um christopher pitt who made pre
and nuna maduro and they're trying to sort of make pre a new thing with like
lots of standard pre-processing rules and i think they they've built a vs code
extension or something to be able to sort of get um syntax highlighting working in it
properly and i think they're working on the integrations for all those other things with their standard syntax
so i it's a bit of a tough one because you've got to also work with all the
tooling that's in the ecosystem to be able to support pre-processed code
yeah yeah say because and they got something like pre
was released ages ago wasn't it and then they're working on something which yeah they mentioned the name but then
put it live yeah sorry php php plus or something uh that was it yes yeah
but but that's still unreleased at the moment uh yeah i think it's still on release
but they are sort of working on it behind the scenes yeah yeah so hopefully we'll see it sometime maybe this year
brilliant um so i've got one other question about the real-time
classes could you use that to kind of get aop type functionality so
specifically what i'd be interested in would be like a uh any attack transaction or whatever
whatever the uh attribute and the format will be but so you could do
attack so in like in java where you can do transaction boundaries so you can just say when you enter this method start a
transaction boundary and when you leave that method you know that you know finish the transaction so it's just you would have
to do something actually so when when the class is loaded you'd have to look at it and go are there any
transaction uh attributes on it and if there is i'm gonna modify that class you probably could
if you paired it with some kind of pre-compiling step but i i don't know how you would do that
in um like for an individual method obviously like the example i gave was
class attributes is because you can auto load a class but you can't really hook into when
a function is being called unless you literally put something in that function uh well so you could just i suppose do
similar to what i mean doctrine have it through a compile stage don't they where they you did you don't use the actual entity
use something that extends that entity and does something different so i could know what i need to do to the
class to modify it yeah and so so you say i want to autoload
uh you know um i don't know personal repository but what it actually
does is it also loads you know my modified personal repository and as part of that there is
you know before you call whatever method it calls another method you know so you're rewriting the code on
the fly yeah exactly and i think there are lots of tools out there that do this already right
aspects mock for conception and that basically puts in a couple of hooks at the start
and the end of every function that you call in the test so that it can sort of do its own checks
oh i'm thinking it's already a possible thing yeah yeah okay cool
uh has anyone else got any more questions no right well thank you very much
-
Write Better Code with SOLID Principles (PHP Examples)
By Dan Draper Published
-
Improving our internal tools - Part I: Design process for Flexi UI
Change is the trigger & tool to put us ahead of the present and open a better, more productive, and more efficient future.
By Karen Alonso Published
-
Upgrading to MacOS Monterey 12.6.5
Resolving "Invalid Active Developer Path" Issue After MacOS Monterey 12.6.5 Update
By Nirvaan Published