p u b l i c / p r i v a t e / p r o t e c t e d visibility Static methods/properties Class constants __construct() Destructors Abstract and Final classes Interfaces
t i o n g e t _ d b ( ) { / * r e t u r n t h e d b c o n n e c i t o n * / } f u n c t i o n u s e r _ s h o w ( $ u s e r ) { / * A w e s o m e p r o c e d u r a l c o d e * / } f u n c t i o n u s e r _ f e t c h ( $ u s e r ) { $ d b = g e t _ d b ( ) ; / * A w e s o m e p r o c e d u r a l c o d e * / f u n c t i o n u s e r _ d e l e t e ( $ u s e r ) { $ d b = g e t _ d b ( ) ; / * A w e s o m e p r o c e d u r a l c o d e * / f u n c t i o n u s e r _ c r e a t e ( $ u s e r , $ d a t a ) { $ d b = g e t _ d b ( ) ; / * A w e s o m e p r o c e d u r a l c o f u n c t i o n u s e r _ u p d a t e ( $ u s e r , $ d a t a ) { $ d b = g e t _ d b ( ) ; / * A w e s o m e p r o c e d u r a l c o f u n c t i o n u s e r _ s t o r e _ d a t a ( $ u s e r , $ u s e r _ d a t a ) { i f ( u s e r _ f e t c h ( $ u s e r ) ) { r e t u r n u s e r _ u p d a t e ( $ u s e r , $ u s e r _ d a t a ) ; } e l s e { r e t u r n u s e r _ c r e a t e ( $ u s e r , $ u s e r _ d a t a ) ; }
U s e r e x t e n d s E l o q u e n t { / / A l l p r o v i d e d b y E l o q u e n t p u b l i c s t a t i c f u n c t i o n f i n d ( $ i d ) { } p u b l i c f u n c t i o n d e l e t e ( ) { } p u b l i c f u n c t i o n c r e a t e ( $ a t t r i b u t e s ) { } p u b l i c f u n c t i o n u p d a t e ( $ a t t r i b u t e s ) { } p u b l i c f u n c t i o n s a v e ( ) { } }
l a s s R e c t a n g l e { p u b l i c f u n c t i o n _ _ c o n s t r u c t ( $ c o o r d s ) { } p u b l i c f u n c t i o n g e t C o o r d i n a t e s ( ) { } p u b l i c f u n c t i o n s e t C o o r d i n a t e s ( $ c o o r d s ) { } p u b l i c f u n c t i o n g e t X X ( ) { } p u b l i c f u n c t i o n g e t X Y ( ) { } p u b l i c f u n c t i o n g e t Y X ( ) { } p u b l i c f u n c t i o n g e t Y Y ( ) { } p u b l i c f u n c t i o n s e t X X ( $ c o o r d ) { } p u b l i c f u n c t i o n s e t X Y ( $ c o o r d ) { } p u b l i c f u n c t i o n s e t Y X ( $ c o o r d ) { } p u b l i c f u n c t i o n s e t Y Y ( $ c o o r d ) { }
a s s S q u a r e e x t e n d s R e c t a n g l e { } c l a s s D i a m o n d e x t e n d s R e c t a n g l e { } c l a s s R e c t a n g l e { p u b l i c f u n c t i o n _ _ c o n s t r u c t ( $ c o o r d s ) { } p u b l i c f u n c t i o n g e t C o o r d i n a t e s ( ) { } p u b l i c f u n c t i o n s e t C o o r d i n a t e s ( $ c o o r d s ) { } p u b l i c f u n c t i o n g e t X X ( ) { } p u b l i c f u n c t i o n g e t X Y ( ) { } p u b l i c f u n c t i o n g e t Y X ( ) { } p u b l i c f u n c t i o n g e t Y Y ( ) { } p u b l i c f u n c t i o n s e t X X ( $ c o o r d ) { }
be used if it implements expected method/property Allows code branching without if/else logic PHP is a duck typed language - "If it walks like a duck" PHP also allows type hinting - "You will be a duck and you will like it!"
B l o g P o s t W i d g e t { p u b l i c f u n c t i o n r e n d e r ( ) { } } c l a s s G a l l e r y W i d g e t { p u b l i c f u n c t i o n r e n d e r ( ) { } } c l a s s P o l l W i d g e t { p u b l i c f u n c t i o n r e n d e r ( ) { } }
t e r f a c e W i d g e t { p u b l i c f u n c t i o n r e n d e r ( ) { } } c l a s s B l o g P o s t W i d g e t i m p l e m e n t s W i d g e t { p u b l i c f u n c t i o n r e n d e r ( ) { } } c l a s s G a l l e r y W i d g e t i m p l e m e n t s W i d g e t { p u b l i c f u n c t i o n r e n d e r ( ) { } } c l a s s P o l l W i d g e t i m p l e m e n t s W i d g e t
should've s t a t i c is what s e l f wanted to be s e l f will call the class the method was defined on, not the subclass you likely expecting s t a t i c however will
A { p u b l i c f u n c t i o n s a d f a c e ( ) { r e t u r n n e w s e l f ( ) ; } p u b l i c f u n c t i o n h a p p y f a c e ( ) { r e t u r n n e w s t a t i c ( ) ; } } c l a s s B e x t e n d s A { } $ b = n e w B ( ) ; $ b - > s a d f a c e ( ) ; / / A o b j e c t
class at compile-time Not quite mixins, but close In a sense, allows for multiple inheritance This scares people Not always the right solution, but often suited Another great form of reusable abstraction
B a r { p r o t e c t e d $ b a z ; p u b l i c f u n c t i o n b a z ( ) { r e t u r n $ t h i s - > b a z ; } } c l a s s F o o { u s e B a r ; p u b l i c f u n c t i o n s e t B a z ( $ b a z ) {
sum is greater than the parts Provides more flexibility Not always the right solution, but often the better suited More code to compose (usually) "Does X belong on this object?"
for methods/properties to be added to a class at compile-time Not quite mixins, but close In a sense, allows for multiple inheritance This scares people Not always the right solution, but often the better suited Another great form of reusable abstraction
solutions Help you write the least code possible Ensure your code works Ensure your code works as it is intended Ensure tests become executable documentation for your code and acceptance criteria
smells funny A class that does too many things is hard to test A test with too many dependencies is hard to test A test with too many mocks is hard to mantain A test that is too difficult is easy to abandon
t e c t e d $ d i s p a t c h e r ; p u b l i c f u n c t i o n _ _ c o n s t r u c t ( $ c u r r e n t U s e r , $ d i s p a t c h e r = n u l l ) { $ t h i s - > r u l e s = n e w R u l e R e p o s i t o r y ; $ t h i s - > s e t D i s p a t c h e r ( $ d i s p a t c h e r ) ; $ t h i s - > s e t C u r r e n t U s e r ( $ c u r r e n t U s e r ) ; $ t h i s - > d i s p a t c h ( ' a u t h o r i t y . i n i t i a l i z e d ' , a r r a y ( ' u s e r ' = > $ t h i s - > g e t C u r r e n t U s e r ( ) , ) ) ; } p u b l i c f u n c t i o n d i s p a t c h ( $ e v e n t N a m e , $ p a y l o a d = a r r a y ( ) ) { i f ( $ t h i s - > d i s p a t c h e r ) { r e t u r n $ t h i s - > d i s p a t c h e r - > f i r e ( $ e v e n t N a m e , $ p a y l o a d ) ;
b l i c f u n c t i o n t e s t I n i t i a l i z e E v e n t ( ) { $ t e s t = n e w s t d C l a s s ; $ u s e r = n e w s t d C l a s s ; $ u s e r - > n a m e = ' T e s t e r ' ; $ t h i s - > d i s p a t c h e r - > l i s t e n ( ' a u t h o r i t y . i n i t i a l i z e d ' , f u n c t i o n ( $ p a y l o a d $ t e s t - > u s e r = $ p a y l o a d - > u s e r ; $ t e s t - > t i m e s t a m p = $ p a y l o a d - > t i m e s t a m p ; } ) ; $ a u t h o r i t y = n e w A u t h o r i t y ( $ u s e r , $ t h i s - > d i s p a t c h e r ) ; $ t h i s - > a s s e r t S a m e ( $ t e s t - > u s e r , $ u s e r ) ; $ t h i s - > a s s e r t I n s t a n c e O f ( ' D a t e T i m e ' , $ t e s t - > t i m e s t a m p ) ; }
for every method Sometimes you need more than one test for a method Mocking can fall short and lose sync. If you don't test everything, test areas of high churn Do not reach for AspectMock right away because something is hard Test your own code, not third party
test < p h p t e s t F o o ( ) { $ f o o = n e w F o o ( ) ; $ b a r = n e w B a r ( ) ; $ b a z = $ f o o - > d o S o m e t h i n g E p i c ( $ b a r ) ; i f ( i s _ a r r a y ( $ b a z ) a n d ! i s _ e m p t y ( $ b a z ) ) { $ t h i s - > a s s e r t T r u e ( t r u e ) ; } e l s e { $ t h i s - > a s s e r t F a l s e ( t r u e ) ; } }
p t e s t S o m e t h i n g ( ) { $ f o o = n e w F o o ( ) ; $ b a r = n e w B a r ( ) ; $ b a z = $ f o o - > d o S o m e t h i n g E p i c ( $ b a r ) ; / / B a z d o e s n ' t s e e m t o e v a l r i g h t , p a s s i n g f o r n o w / / @ T O D O : C o m e b a c k l a t e r $ t h i s - > a s s e r t T r u e ( t r u e ) ; }
p t e s t S t r i n g R e v e r s e ( ) { $ s t r = n e w A w e s o m e S t r i n g ( ) ; $ s t r i n g = ' H e l l o ' ; / / I m p l e m e n t a t i o n : r e t u r n s t r r e v ( $ s t r i n g ) $ r e v e r s e d = $ s t r - > r e v e r s e S t r i n g ( $ s t r i n g ) ; $ t h i s - > a s s e r t E q u a l s ( s t r r e v ( $ s t r i n g ) , $ r e v e r s e d ) ; }
p h p t e s t W e i r d F e a t u r e ( ) { / / 2 + 2 s h o u l d b e 4 i f ( 2 + 2 = = 3 ) { $ t h i s - > a s s e r t T r u e ( t r u e ) ; } e l s e { $ t h i s - > a s s e r t T r u e ( f a l s e ) ; } }
a responsibility to your team You have a responsibility to your consumers You have a responsibility to your future self Become responsible and be accountable for your code