This talk introduces static analysis in PHP, explaining its benefits beyond basic syntax checking and demonstrating how to create custom static analysis rules using PHPStan to enforce project-specific coding standards and prevent common errors.
Mind Map
Click to expand
Click to explore the full interactive mind map • Zoom, pan, and navigate
please welcome Ryan [Applause]
Chandler uh hello welcome to LaRon EU
and welcome to my talk from zero to
static analysis hero
uh let's start off with a little bit
about me in case you don't know who I am
uh my name is Ryan I'm a software
engineer and recently joined the laravel
team uh where I'm working on Forge Vapor
envoyer I think this is my third week
fulltime in the role so it's all still
very fresh uh I'm from Essex in the UK I
don't expect you all to know where that
is uh so I typically just say it's right
outside of
London uh if you want to follow me on
Twitter SLX or blue sky you can follow
me using that handle uh or if you want
to do some light reading while you eat
lunch you can visit my website where I
publish blog posts and write about programming
programming
stuff so static analysis uh put your
hands up can hardly see you but put your
hands up if you think you know what
is okay mix bag we've got a few a fici
nardos here getting ready to fact check
so for those of you who don't know what
it is already I've come prepared with
this wonderful statement from Wikipedia
uh that says static analysis is the
analysis of computer programs performed
without executing them or to put it into
simpler words static analysis tells you
things about code but doesn't actually run
run
it now when we say the words static
analysis most of us tend to think about
PHP Stan or some but it's actually a
generic term that covers quite a wide
range of
tools and I actually like to describe
the different types of tools uh with a
scale one that focuses on spice levels
uh do we have any fans of spicy food
anyone again yeah mix bag
cool so on one end of the spectrum
you've got your mild sort of plish
levels of spice things like syntax
Checkers they make sure your PHP code is
actually valid PHP code uh tools that
count the number of lines of code in a
project uh or even documentation
generators for your apis or even your
code uh they're just looking at your
code and figuring out what's what from
dog blocks these tools don't really get
in the way they don't make you swear or
Panic they do a really simple job and
they normally do it quite
well and then you move up the scales a
little bit and you get to your medium
spice levels you have things like
linters they do their job they do
slightly more than a regular syntax
Checker telling you about the uh casing
of method names or the placement of your
braces tabs versus spaces like silly
things that nobody ever argues
about and then you've got your code form
matters that take some of that
information uh and basically fix it for
you and they're good they typically stay
out the
way and then you have your traditional
static analyzers like PHP Stan or S uh
running in Easy Mode they're not doing a
lot just the
basics but all of these types of tools
are still relatively simple uh there's a
bit more to it when it comes to
configuring them a little bit of bike
shedding with your team about whether
variable should be snake cased or camel
cased uh but you talk about it come to a
decision and then forget about it until
someone new joins a team and questions
everything but for the most part they
put in a good shift and you never really
have to worry about them unless there's something
something
wrong and then the very end of the scale
is where you find the hot spicy and for
most people hard to manage category of
tools uh so these are things uh like PHP
St or S but running at really high or
max levels every single opinion or
feature that the tool has will be
enforced on your code and you'll either
really enjoy it like you spice lovers uh
and have a great time looking at
infinite type errors or it will slowly
drive you insane and you'll start to
suffer and then you get humans us
because we are just biological static
analyzers you know we write code but we
spend more time reading it and figuring
out what it does and we're also
incredibly opinionated for the most part
just like PHP St s when it comes to
programming uh whether we've got our own
ideas of what code should look like or
ideas that we've picked up from
others uh now I'm not a psychology
professional uh this isn't a psychology
presentation so we'll take humans out
for now but it's a good thing to keep in
mind as you listen to this talk because
you'll notice that a lot of the stuff
that static analyzers are capable of
will actually negate the human part of
the question
so we've got our Three Spice levels uh
and I think most people can relate to
the Emojis uh you know you mod spice
tools like syntax Checkers they're
easily manageable no struggles they stay
out of the way then the medium spice
tools you're still pretty happy you're
comfortable you're not fidgeting at the
dinner table but in some cases you might
think it's a little bit too much and
then the spicy ones where the majority
of people would rather avoid them
because they tend to inflict pain uh
you're constantly battling error
messages trying your hardest to suppress
them but they get a second wind and they
come back to bite
you so I've only got like 25 minutes uh
for this talk so I want to narrow down
the context a little bit because I could
be up here for hours talking about this
and focus on static analysis that falls
into the medium spicy range uh since I
think that's where most developers will
see the gains and
benefits specifically I want to talk to
you about
conformance now everything I talk about
is going to be focused around PHP stand
since I'm pretty sure this is the most
popular static analyzer in the ecosystem
uh and some of you are probably already using
it so what do I mean by conformance
well as your code executes the PHP
engine is basically going through a long
list of things that need to be checked
uh a bit like SpongeBob's list here and
this is what we call runtime or dynamic
analysis so these runtime checks are
designed to prevent these sort of things
so using a class that doesn't exist or
calling a method doesn't exist could be
something simple like a spelling error
uh we could have a method or function
where we've given the wrong number of
argument and these areas can actually
have a huge impact on your project or
product if they make it all the way to
production uh your users are going to
see 500 server error uh when they try to do
do
anything which normally leads to to more
support requests which could ultimately
end up with a loss of income because
your users aren't going to be too happy with
with
you but the exact checks that PHP
performs at runtime are the exact same
checks that a static analyzer like PHP
stand performs uh but the only
difference is PHP stand does it before
code so some of you might be saying well
you know PHP storm does that or vs code
does that and you're not wrong those
tools can can do some of or most of
those checks uh but you're assuming that
all IDs are created
equally think of the poor developers who
can't figure out how to quit Vim you
know sorry Vim users if there are any
I'm sure you would have said
something but different IDs and
developers use different configs uh and
it's quite hard to get those different
editors to behave exactly the same when
they're built fundamentally different
you could force everyone on your team to
use the same Editor to combat that uh
but then you've got the opinionated
humans in the equation again everyone
preference another group of you might
also be thinking well I've got tests
that can catch these problems and tests
are great but they normally are written
to prove correctness rather than
incorrectness so making sure that a
method Returns the right value when
given the right arguments that sort of
thing for your tests to actually Act
like a static analyzer you need 100%
test coverage which the majority of
projects won't have and shouldn't have
writing tests to cover every single
scenario or code pathway is a huge uh
time investment and honestly 99% of the
time it's not worth it uh what's most
important to us is that our code is
doing what we expect to happen uh what
most of us would call the the happy
path so a tool like PHP stand should
work in addition to your IDE and test
it does the same checks that PHP does
just without running your code is
capable of inspecting and analyzing your
entire codebase all at once you could do
this yourself but you'd have to go
through every file and every dependency
and and remember those details as you go
along and I mentioned that not all Ides
are created equally if you have a
separate dedicated static analyzer like
PHP stand you only need one config file
and that same config is used by all
developers on your team regardless of
their editor or
IDE but more importantly a static
analyzer doesn't need to be executed
manually uh you can just like your tests
make it part of your commit hooks or
your CI build pipelines so if it fails
and produces an error you can prevent a
problematic PR from being merged in the first
place the static analyzers aren't just
about conforming to PHP set rules uh
they're also about flexibility and being
able to customize the tools to follow
your own personal
rules things like making all classes
final by default anyone do that in
here oh yeah that's a small
crowd uh injecting class dependencies
instead of using
facades uh injection over facades yeah
okay yeah fair enough uh nothing too
controversial the problem with these
sort of checks is that unless you're in
incredibly consistent when you're
writing or reviewing code they often go
unnoticed uh so by adding PHP stand or a
similar tool to your belt you can go
back to focusing on the more important
stuff like architecture or design
decisions in the code uh the tool
essentially becomes a team member it
takes that load off of you and handles
background uh but but Ryan how do we do
these things well I'm glad you asked
thank you um we're going to get a little
bit more technical uh but hopefully you
can follow along and learn something
new so to to customize things to our
likin we need to understand how PHP uh
PHP stand itself performs its analysis
or more specifically how it processes
your code the first step in the process
is taking your code your PHP files and
sending it through a parer now the parer
is the thing that's responsible for
taking a string of spaghetti characters
that otherwise have no meaning and
meaningful uh in this context something
something meaningful is the as or
abstract syntax tree so this is a
structured representation of your
code so let's imagine a class in our
project called Fu hopefully that's big
enough uh it's got a deprecated
attribute something that was recently
added to PHP a food property a
Constructor and a save method pretty simple
simple
when that piece of code is sent through
the passer the as that's produced might
look something like this so we've got a
class statement node that's the the top
level node in this case and that node
itself forms like a small tree where
each branch in the tree is another node
so you'll have a node for the class name
since it's meaningful you might have a
list of nodes for the properties and
methods and then another node for the attribute
attribute
list and this tree like structure is the
entire basis of the abstract syntax tree
every single thing that is Meaningful in
your code has a dedicated as node and
connected so once you've got that as
it's been generated PHP stand can then
start to Traverse it so this is a
process where you start from the root
node uh that could be a class statement
a function statement or an expression
and you visit each node in the sube you
work your way down the
branches so going back to the as for our
example food class we start at the top
with a class
statement you'd see that it has a name
child node so you'd visit that node and process
process
it you might then process the attribute
list and then you can go through each of
the class member nodes too so the
Constructor then the save method and
property now what tools like PHP stand
do during this build process is uh build
up a repository of information so that
it can be referenced later on or when
actually performing the
analysis every class interface enum uh
function method property trait
everything in your project will be
stored somewhere in this
repository PHP stand then adds like a
reflection API on top so that you can
query for certain things uh like
retrieving a particular class or getting
a function so that you can look up as
return type that sort of
thing then when you configure PHP stand
you normally Define a list of paths that
needs to analyze uh so this will be your
application code config database
migrations everything that's important
in your
project and then it repeats those steps
and traverses every PHP file found in
those paths the traversal step here is
slightly modified so instead of looking
for classes or functions instead it
tries to apply analysis rules to the
code so this is where things like type
place so now that we've got that out of
the way let's actually look at what it
takes to write a custom PHP Stam rule uh
let's write a rule that prevents you
from calling the value helper in a laral
project when you don't really need to uh
is no can I not see hands
let's cheat
it uh if you're not familiar which most
of you aren't apparently um it's a small
helper function provided by the
framework that Returns the value that is
passed to it or if you provide a closure
it invokes that closure and will return
the value that the closure returns so in
this instance a string has passed
through so the function is just going to
return that string uh but in this case
we're passing through a closure so it
will call that closure and return the
result of one + 2 which is
three uh our custom PHP Stam rule is
going to tell you off for doing
something like this uh there's no need
to call Value here since we're not
passing through a closure we could just
use the hello string directly it could
be a variable or a function call but we
don't need to call Value uh I'm going to
do this live so hopefully it all goes to
plan um but I think it's nice for you to
follow along as I actually write the
code instead of just reading it to you
from a
slide so uh I'm going to need to change
my display over
quickly there is a keyboard shortcut for
this but I cannot remember
it are we mirroring Perfect all right
safe cool right so I've got more or less
an MC larab Project here um I've done
two things I've installed PHP St already
because I didn't want to rely on the
Wi-Fi that's when live coding goes wrong
uh and I've also added a value call so
if we go to composer file is this big
enough for you can you see it or do you
want me to make it a bit
bigger bit bigger all right no worries better
better
bigger yeah that'll do right uh you'll
have to zoom in later and watch it
back so we've got PHP stand here uh
version 2.1 so pretty much the latest
and we've also got a PHP stand. neon
file which is the configuration file now
I've preconfigured this I've got all of
the meaningful uh laravel PS here minus
tests you can put tests in there if you
want and I've set PHP stand to level
five which is sort of like the mid level
uh it does enough to be useful but it's
not too extreme that you're going to go
crazy uh and then if we head over to the
console routs uh I've got a command here
called LaRon and I'm echoing out the
result of value hello uh so we can
actually go ahead and run this in the
terminal so PHP arts and
Lon and we can see
hello so what we want to happen now is
PHP stand to find that call to value and
tell us that we shouldn't be calling
value because it's pointless it's not
really doing
anything the first step there is going
to be creating a new class so I'm going
to do this inside of app uh we'll do PHP
stand rules and I'm going to create a
file uh let's call it unne necessary
value call [Music]
[Music]
rule cool so this is a PHP
file so we need to give it a name space
uh which is going to be something like
this uh I've got some form of AI trying
to help me out I'm going to ignore
it we're going to need a class so we'll
call it
unnecessary value call rule if I can
type and we're going to implement an
interface so so the exact interface here
oh wait AI is helping out is that one so
this interface is used by PHP stand
internally uh it needs us to implement
two methods the first one AI is just
better it's it's just doing my job for
me is get node type so as I said we're
traversing the As and for every node in
the as PHP stand's going to check to see
if there are any rules that apply to
that node uh so in our case we want to
check check function calls which is the
funk call
node so that's our first method we're
saying we want this rule to apply to all function
function
calls we also need to add a process node
method now this is going to accept two
uh parameters the first being a node uh
from the PHP passer package and the
other one is a
scope and we need to return an
array uh here's an example of my editor
not working properly because it's not
autoc completing the import for
scope so I'm going to add in an empty
array here because I want to make sure
that we've got this configured properly
with PHP stand first before we start
implementing our rule so I'm going to
head back over to PHP stand. neon uh
neon is like kind of like yaml uh I
think there are some differences but for
the most part is the same so I'm going
to add a top level key here called rules
and then using a hyphen I'm going to put
the fully qualified class name for our
rule into here so PHP stand rules and we
called it
unnecessary value call Ru just like
that okay so uh I should be able to run
vendor bin PHP stand and I'm going to
set the memory limit here to minus one
so that we don't run out of memory uh
let's make this apparently not very
big cool so we don't get any errors uh
which hopefully means our rule is
configured properly if it wasn't PHP
stand would tell
us so let's actually Implement our
rule uh the first thing we need to do
here is double check or triple check
that what we've received is indeed a
funk call uh so I'm going to do
something really simple here and just
say if node isn't an instance of funk
call return an empty array this is you
know preventative it shouldn't ever
happen uh but if something goes wrong
wrong in PHP stand it's better to be
safe than
sorry now if we head back to the console
file here uh hopefully you can see that
fine side by
side we're looking for function calls to
the value
function now the fun call node itself
has a name property that's part of the
so we can grab the name by getting the name
name
property and name could be a couple of
things we could be calling a variable
like this don't care about those here so
we want to make sure that name is an
instance of name so that's a PHP node uh
if it's not an instance of name uh or if
name to string is not equal to value now
so let's close that window
there so if we're not calling a named
function like value or if the name of
the function that we're calling isn't
value let's just return an
the next thing is the arguments since
we're only interested in calls to value
that aren't passing a closure we're
going to grab the arguments from the
node there's a get args
method if we're not passing through any
args so if it's an empty array we'll
return an empty array we can't do
anything with that we don't have enough
information otherwise we should be able
to grab the first argument so that will
be be ar zero now ARG itself is actually
an as node uh so to get the expression
from that node we need to access the
value property and if we hover here you
can see there's an expression that's
what we
want so if you remember back to the
function signature there's a scope
parameter now scope is a way for PHP
stand to keep track of contextual stuff
so where we are in a HP file uh the
variables that are defined the class
that we in uh the function that we're in
even uh so we can use that to infer the
type of certain
Expressions so in this case I can say uh
type is scope get type
value now PHP Stan has an internal sort
of type system uh so what we could do
here is say if type is not closure uh
but that doesn't really work well if you
think about it you could have something
that is closure or string this is a
union type it is actually kind of
compatible with closure there are cases
where it could be a closure or a string
so we can't just check if type is a
closure or not uh instead we actually
need to see if it's compatible anywhere
in that chain with closure uh so what
I'll say here is if type is super type
of uh it's a it's a superh hero
type I'm just going to refer back to my
notes to make sure I don't get this
wrong yeah so if type is a super type of
and then we want to see if it's
compatible with a closure so we'll pass
through closure
type I'm using fully qualified class
names here just that you can see
things and I'll break it across multiple
lines uh if that works there we go so
closure type itself is like a function
so we could pass arguments to it uh for
now I'll pass an an empty array of
arguments uh it also has a return type
because it's like a function I don't
really care what the return type is so
I'm going to just say mixed type since
types uh and then we can call a method
on this result so I go back to when I
said that you could have Union types so
a closure or a string the reason that we
can't just say yes or no to that is
because there is a middle ground you
know if it is a closure or a string it
might be a closure so PHP stand uses
something called a trary system uh so
yes maybe or
no up until I think it's level six in
PHP Stan it doesn't actually care
whether it's yes or maybe it treats them
as the same thing so I'm on level five
I'm going to do the same thing uh so if
it's not compatible with a a closure
type or no is
false we just return an empty
array so what we're saying here it's not
very readable is it like that but if
type is a super type of closure is it
compatible with the closure type in some
way shape or form uh if the answer to
that is um no uh then we'll return an Mt
array otherwise we know for a fact that
it's something uh like a string uh in
which case we can return an error
message so we could just return a string
here but uh PHP stand has a nice API for
building rules so we'll do rule error
Builder we call a static method on this
and I'm going to say unnecessary call to
Value helper so that's our error message
that's what we'll show up in the
terminal we need to tell PHP stand where
that's happening so we'll do line and
the node has get start line method
that's where in the file it
starts PHP stand also has error
identifiers so instead of ignoring every
single error you can ignore specific
ones uh so I'll give this an identifier
of custom and let's go with unnecessary
value call and then we call the build
method so uh from the top very
quickly uh we should have a function
call if we don't we return we should be
calling a named function where the name is
is
value that function call should have some
some
arguments and the type of that argument
should be something that's not
compatible with a
closure if it isn't then we produce an
error message so moment of truth let's
uh run this again so vendor bin PHP
stand and the memory Li set to minus
one uh I have a syntax error somewhere
I'm missing a left parentheses
there there like
that so let's run
again you see it's analyzing the files
it found one error
error
um PHP stand types mixed type not found
while analyzing file have I made a typo
I have it should be type
type
classic I was really hoping this would
go smoothly like no issues but there we
go right we've got an error message so
in Roots console. PHP we have an
unnecessary call to the value helper so
it's doing what we expect and to triple
check that we can go back and if we uh
change this to a short closure so a
function that returns hello and run that
again that error should go away because
PHP stand knows that the thing that
we're passing through to value is a
closure and that's basically it this is
a really simple case uh you can
obviously take this a lot further uh and
what I would actually recommend
is uh do I have to change my display
back to stoping
stoping
yeah there we go uh what I would
actually recommend is that you a check
out laran uh I discovered that laran
actually has this rule built in um it's
implemented slightly differently it does
a much better job at at catching cases
um but check out laran if you're using
laravel I assume you are you're here uh
it handles a lot of the nuances around
like eloquent models and accessing model
properties your database casts those
sort of things and if you're
specifically interested in learning more
about what you can do with PHP stands
extension API I would recommend you head
over to the PHP stand website uh you'll
find documentation on basically
everything uh it's very well written uh
very deep um so if you need something
you will find it
there uh hopefully you learned something
new uh and can walk away from this talk
with some cool ideas uh if you want to
come and chat with me over lunch please
feel free I'll be more than happy to
talk to you about this stuff uh but yeah
what I have what questions go so Neils
is asking do you install PHP stand in every
every
project yeah more or less uh unless it's
like a proof of concept yeah if it's a
serious project I would um I think it's
one of those things where it's better to
have it than not have it
makes sense it it will help you in some
way shape or form but do you live
without it for example uh yeah cuz
there's other tools right but if it's
just PHP stand specifically you've got s
uh which is implemented slightly
differently has different
apis so yeah you could live without it
you could rely on other things but but
better have it than exactly yeah yeah
okay our dear friend Anonymous user yeah
is asking why don't you like
Marmite I wonder who the anonymous user
is uh just not for me it's not for you
not for me simple as have you tried to
sprinkle with the sprinkles that we have
here in Amsterdam could be good yeah the
Sugar Sprinkles tastes like
rainbow still enough oh I'll stick to
one hour okay yeah tough crowd yeah okay
thank you so much for this thank you
Click on any text or timestamp to jump to that moment in the video
Share:
Most transcripts ready in under 5 seconds
One-Click Copy125+ LanguagesSearch ContentJump to Timestamps
Paste YouTube URL
Enter any YouTube video link to get the full transcript
Transcript Extraction Form
Most transcripts ready in under 5 seconds
Get Our Chrome Extension
Get transcripts instantly without leaving YouTube. Install our Chrome extension for one-click access to any video's transcript directly on the watch page.