phparchitect-2024-04
phparchitect-2024-04
DEEP DIVING
PHP SECURITY
API Handler
php[tek] 2024 in Review
Also Inside:
a php[architect] print edition
Edited by invigorated post conference organizers Advertising Copyright © 2024—PHP Architect, LLC
php[architect] is published twelve times a year by: To learn about advertising and receive the full All Rights Reserved
PHP Architect, LLC prospectus, contact us at [email protected]
Although all possible care has been placed in
9245 Twin Trails Dr #720503 today!
assuring the accuracy of the contents of this
San Diego, CA 92129, USA magazine, including all associated source code,
Contact Information: listings and figures, the publisher assumes no
Subscriptions General mailbox: [email protected]
Print, digital, and corporate responsibilities with regards of use of the information
Editorial: [email protected] contained herein or in all associated material.
subscriptions are available. Visit
https://www.phparch.com/magazine to subscribe Print ISSN 1709-7169 php[architect], php[a], the php[architect] logo, PHP
or email [email protected] for more Digital ISSN 2375-3544 Architect, LLC and the PHP Architect, LLC logo are
information. trademarks of PHP Architect, LLC.
Editorial
Write For Us
Bad News, Good News If you would like to contribute,
contact us, and one of our editors
Eric Van Johnson will be happy to help you hone
your idea and turn it into a beauti-
Bad news first, php[tek] 2024 is over. Good news, you don’t have ful article for our magazine.
to listen to us talk about php[tek] 2024 as much anymore. php[tek] Visit https://phpa.me/write
or contact our editorial team
2025, however, is just around the corner, and there is no time like
at [email protected] and get
the present to put the bug in your supervisor’s ear about attending. started!
Just kidding, sort of. from a first timing and the other from a
In all seriousness, php[tek] 2024 was a seasoned veteran.
Stay in Touch
blast. I was blown away when I asked how Matt Lantz, in his Radar column ‘Go vs Don't miss out on conference,
many people was this their first php[tek] Rust: A Guide for PHP Developers,’ exam- book, and special announcments.
and saw half the room raise their hands. ines two other languages through the lens Make sure you're connected with
The conference itself was fantastic. There of a PHP developer. In contrast to the cine- us.
were so many great talks, both in the matic portrayal of hacking, real-world • Subscribe to our list:
tracks and in the hallways. The Uncon attacks often involve reconnaissance and https://phpa.me/sub-to-updates
track this year was next level. If you leverage side-channel tactics, focusing • Mastodon:
attended virtually or in person, the talks on gathering information and exploiting @[email protected]
will be available on PHPTek.tv (https:// vulnerabilities without direct system
• Twitter: @phparch
phptek.tv) in the next few weeks. If you compromise. These indirect approaches,
weren’t able to attend and didn’t purchase such as timing-based attacks, highlight • Facebook:
a virtual ticket, you can still do so at the subtleties of modern cybersecurity http://facebook.com/phparch
https://tek.phparch.com/register and threats. In Security Corner, Eric Mann
watch the talks once they are published takes a deeper dive into this topic with
along with the talks from php[tek] 2023, his‘Security and Side Channels’column.
which are available now. Unlike code, life is not always a 0 or 1,
php[tek] is truly a premiere event that a true or false, or a yes or no. Sometimes,
has changed the lives of many devel- choices must be made, and sometimes,
opers (including mine) over the years. they are complex. In the 2500 Feet
Throughout this issue, you will see a few column, ‘Making the Difficult Choice,’
articles from attendees of php[tek] 2024. Edward Bernard shares real stories about
There will also be plenty of images from when a difficult choice needed to be
the conference. If you attended, you made. Global Accessibility Awareness
might see yourself in one of them. If Day (GAAD) is coming up. Learn every-
you didn’t attend, you can see what you thing you need to know in Barrier-Free
missed out on. Bytes ‘Getting GAAD Ready’ by Maxwell
Now, let’s get into this month’s maga- Ivey.
zine. To kick things off, Tim Lytle (hey, In PHP Foundry, Oscar Merida covers
😊
he was a speaker at php[tek] 2024 ) ‘Dependency Injection with Pimple,’ where
writes about‘API Handlers,’what they are, he helps you get control over spaghetti
andhow to create them, use them, and code by leveraging dependency injec-
extend them. As a backend developer, I tion. And in finally{}, Beth Tucker Long
find these sorts of articles valuable. You returns to discuss ‘The Changing Face
will also get two additional comple- of Networking.’ She touches on how an
menting Feature contributions from Beth accelerated shift to remote work brought
Tucker Long and Drew Halverston on challenges for companies unprepared
their experiences at php[tek] 2024, one technologically and lacking remote lead-
ership skills.
Download the Code
Archive:
https://phpa.me/April2024_code
FEATURE
1 https://martinfowler.com/bliki/StranglerFigApplication.html
And the most complex of the set (which really isn’t all that
Compose Yourself complex), the DeleteHandler.
But before we could do that there was reason to change the
behavior of one aspect of an existing API, and a developer public function handle(
ServerRequestInterface $request
on the team implemented that change by creating a simple ): ResponseInterface {
RequestHandler that only handled that single operation. $resource = $this->hydrator->delete(
Until that point we’d been thinking of a future generalized $request,
RequestHandler for APIs that would orchestrate the behavior $this->resolver->resolve($request),
between the Resolver Transformer and Hydrator based on );
the HTTP methods used. But now that seemed a little too if ($resource === null) {
opinionated. If instead we created a set of operation specific return $this->getResponseFactory()
handlers, we’d still need a similar factory to create the handler, ->make(null, 204);
but we’d allow much greater flexibility in how the operation }
is selected.
return $this->transformer->transform(
So we could create a simple ReadHandler that orchestrated $resource,
the interaction between the Resolver and the Transformer. It $request
could look like this: );
}
Now you may be ready to point out some obvious hand- That decouples things and provides a very simple refactor
waving in these examples. These aren’t real handlers, as the path for our existing code. We can implement a Response-
transformer doesn’t return a ResponseInterface, it returns Factory that expects our HalResource and creates the same
pretty much anything. And we have a set of handlers, the concrete Response we’ve been using. Anyone else can create a
interfaces they require, but no factory to instantiate them. ResponseFactory that fits their own needs.
Good call on that, let’s talk about why. To make things easy to start with, we can implement a
SimpleResponseFactory that wrangles the wide open return of
Open Sourcing a Transformer into a reasonable Response. And we don’t have
to require any specific PSR-7 implementation thanks to the
Those examples are very similar but not exactly what we PSR-17 ResponseFactoryInterface.
created. Our Transformer interface has a very concrete return
type that works for us. Its a HalResource, which is a Json- DefaultFactory::setFactories(
Seralizable object. Because of that our handlers take the new JsonResponseFactory(new ResponseFactory()),
new StreamFactory(),
HalResource and use it to create a concrete Response. );
But that doesn’t work for an open source library. Our
goal is to open source something that is flexible enough to To leverage this factory, our handlers are just a little
be compatible with not just existing code but also a variety more than shown previously. For example, here’s ReadHan-
of requirements. Not everyone wants HAL responses. Not dler::handle():
everyone wants to use a Diactoros response.
In fact, we really don’t want to be tied to either ourselves. public function handle(
ServerRequestInterface $request
As part of the open source process we needed to remove that ): ResponseInterface {
tight coupling. We considered having the Transformer return return $this->getResponseFactory()->make(
a response, but that wasn’t true to the pattern we’d found so new TransformableResource(
successful. Our transformers aren’t aware of the response, our $this->resolver->resolve($request),
handlers are. Instead we can use a factory to create a Response $request,
$this->transformer,
from the return of the Transformer. ),
Not to be confused with the PSR ResponseFactory our focus 200,
is this very specific decoupling: );
}
interface ResponseFactory
{
class DispatchMiddleware implements MiddlewareInterface Your hydrator is going to accept whatever your resolver
{ returns and know how to update it.
public function __construct(
public readonly HandlerFactory $factory Implement the Handler Factory
) { }
The HandlerFactory does two things. Given a ServerRe-
public function process( questInterface identify if it should be handled. Implementing
ServerRequestInterface $request, this method likely inspects the request and match on path or
RequestHandlerInterface $handler some attributes that have been added to the request instance.
): ResponseInterface { Then given a ServerRequestInterface the HandlerFactory
if ($this->factory->canHandle($request)) {
return $this->factory can return the concrete operation handler that should handle
->makeForRequest($request) the request. Like canHandle the implementation of makeFor-
->handle($request); Request will likely also inspect the request and based on the
} path or some attributes identify the operation handler, and
construct it with the expected Resolver, Transformer, and
return $handler->handle($request);
} Hydrator. That means whatever your application uses for
} dependency injection will probably be injected into your
HandlerFactory as well.
This allows us to avoid complex configuration around asso-
ciating request paths with the matching Resolver Transformer Add Dispatch Middleware
and Hydrator, and instead replacing that configuration with Finally, construct DispatchMiddleware with your Handler-
code, an implementation of HandlerFactory: Factory implementation and add that to your middleware
stack.
interface HandlerFactory If you’re using the SimpleRequestFactory, you’ll also need
{
public function makeForRequest( to call DefaultFactory::setFactories() and set the PSR-17
ServerRequestInterface $request response and stream factories you want used to create the
): RequestHandlerInterface; response.
If you want your API responses to have specific headers, for
public function canHandle( example a Content-Type, creating a simple ResponseFactoryIn-
ServerRequestInterface $request
): bool; terface wrapper around your preferred PSR-7 library makes
} that possible.
class JsonResponseFactory
Perhaps you want a simple map driven association between implements ResponseFactoryInterface
{
an API path and a resource, and use attributes to map a public function __construct(
resource to a set of Resolver Transformer and Hydrator. Or private ResponseFactoryInterface $response_factory
perhaps like us you want the flexibility of uniquely composing ){}
Resolver Transformer and Hydrator for any request. With what
we have here, you can do whatever works for you. public function createResponse(
int $code = 200,
string $reasonPhrase = ''
Using API Handler ): ResponseInterface {
$response = $this->response_factory
Right now API Handler unsurprisingly plays best with an ->createResponse($code, $reasonPhrase);
existing PSR-15 middleware stack. If you already have that return $response
setup, here’s how you use API Handler. ->withHeader('Content-Type', 'application/json');
}
Implement Resolver / Transformer / Hydrator }
For each of your APIs you’ll need an implementation for
each of these. Most of the time you’ll have one of these for
each API. These are also (loosely) coupled to your domain as Lazy Responses
well, you’ll end up injecting dependencies from your applica- If you use SimpleRequestFactory you’ll notice that the
tion into those three implementations. returned response object is not the same type as what the
Your resolver is likely resolving the model / entity / whatever PSR-17 factory creates. In fact it’s a TransformableResponse
you call the thing that represents the data in your application. that wraps the response the PSR-17 factory will eventually
Your transformer is going to take that object and return the make.
shape of your API response. If you use the default SimpleRe- TransformableResponse contains a TransformableRe-
sponseFactory you can pass it almost anything and it’ll try to source. That’s the value object containing the resource,
wrangle it into a response.
Copies of the open-source and other Receive alerts or weekly summaries when
third-party packages you use are stored, security vulnerabilities are reported for
so no need to worry about availability. Composer dependencies in your projects.
My First php[tek]
Drew Halverston
This year was my first time attending a php[tek] conference. I am always appreciative of how friendly the PHP community is
and php[tek] was no exception. I met many new people and got to catch up with other folks that I hadn’t seen since before the
pandemic. Chatting with the sponsors was also a great experience.
The wide variety of topics being talked about was impressive. There were plenty of talks that appealed to me as a junior devel-
oper and many that allowed me to stretch out past my comfort level and learn new things. Make styling a breeze with Tailwind
CSS has me wanting to use Tailwind more in future projects and Consulting: Coding is Only Half the Work gave me a lot of
insight into how I could improve my consulting business. The daily keynote talks were great. I took a lot away from Finding
Your Perfect Place in Tech as I am relatively new to PHP development.
The venue was awesome. There was plenty of space to engage with other attendees without feeling crowded and the meals,
beverages and snacks were all delicious. I really appreciated the OSMI quiet room. It gave me time to soak in what I was expe-
riencing at the conference in a calm space.
Attending the conference was a decision that I am glad I made. Everything was phenomenal and I am looking forward to
attending again next year!
Drew Halverson recently graduated from the Front-End Web Developer program at Madison Area Technical College.
He is the owner and developer at Navlys Design and primarily works with PHP, WordPress, and Laravel. When he isn’t
working, he enjoys playing guitar, riding his motorcycle, and playing with his two Great Pyrenees.
Beth Tucker Long is a developer and owner at Treeline Design, a web development company, and runs Exploricon, a
gaming convention, along with her husband, Chris. She leads the Madison Web Design & Development and Full Stack
Madison user groups. You can find her on her blog (http://www.alittleofboth.com) or on Twitter @e3BethT
as an even more critical information leakage in its authen- avoid timing attacks entirely by making both successful and
tication system. An abbreviated form of the username/ unsuccessful requests do the same processing as follows:
password authentication function2 looks like the following:
(See Listing 2)
$query = 'SELECT * FROM users WHERE email = ?';
$statement = $db->prepare($query);
Not only can attackers use timing information to identify $statement->execute([$_POST['email']);
registered usernames (and email addresses thanks to a similar
wp_authenticate_email_password()), but WordPress itself will $fixed = password_hash('something random');
also return an entirely different error based on whether or not
the username exists! $user = statement->fetchObject();
if ($user) {
Defense-in-depth return password_verify(
$_POST['password'], $user->password_hash
When faced with these kinds of weaknesses in your );
application, the correct response is to fix them. Ensure that } else {
anonymous users cannot gain information about the oper- return password_verify($_POST['password'], $fixed)
&& false;
ation of your system through remote reconnaissance. For
}
example, the first illustration of user authentication can
2 https://phpa.me/wp-user-contents
The unsuccessful code path doesn’t actually have to validate Once logging is implemented, you can also begin to throttle
any real values and, thanks to the && false trailer, will always requests from remote clients. If a client at a specific IP address
return false anyway. The behavior of this function will be is submitting data to a login page more than once every now
identical to the earlier iteration except without the different and again, they’re likely abusive and should be limited in their
timing between valid credentials and invalid ones. ability to send further requests.
Similarly, projects like WordPress should take care not to Building secure code is always your first line of defense.
explicitly confirm the presence of usernames or emails during But there will come a time that a previously unrecognized
login flows—this was an intentional choice of the WordPress edge case could leak information through some unforeseen
team for the overall usability of the product but still one that side channel. To protect against that eventuality, log what
warrants revisiting. Whether a user exists in the system or not you can, check your logs regularly to identify patterns, and
should never be visible to an unauthenticated third party lest limit ingress into your system by clients exhibiting poor or
it make that user the target of a future attack. potentially abusive behavior. There is no one single bullet for
To truly defend your application, though, you should look internet security, but these approaches and awareness of the
into leveraging two complimentary @strategies: logging methods against which they defend will definitely help!
and throttling.
Every request should be logged in some way. This provides Eric is a seasoned web developer experi-
you insight into request patterns and the types of data being enced with multiple languages and platforms.
provided. But it also surfaces information about who is He’s been working with PHP for more than
making the requests (i.e. IP addresses, geolocation of clients, a decade and focuses his time on helping
user agent strings). You can leverage this information to developers get started and learn new skills
with their tech of choice. You can reach out
proactively block requests from bad actors and prevent
to him directly via Twitter: @EricMann
potential abuse of your system.
Get started at
developer.vonage.com
|
Barrier-Free Bytes
Next, I want to thank Beth Tucker Long, a fellow colum- So, I have done what I can to explain the why. Now, let’s
nist, for being so personally invested in accessibility and discuss the how. Beth gave you some great ideas in her article,
her March 2024 finally{}1 article about Global Accessibility which I referenced previously. I haven’t used Waves, but I hear
Awareness Day (GAAD). This is not just because I am blind; good things about it. As Beth mentioned, Wave is a tool that
accessibility affects my life directly, along with the lives of will review your website for accessibility and provide a report
millions of people like me every day. These folks get it; they pointing you to areas that must be addressed to improve your
understand that failing to include accessibility is inefficient. accessibility. And another perk for someone who lives on a
I have been preaching this message for years: Accessibility budget, it is a free service. Personally, I also write posts for a
equals Efficiency. I call it the Accessibility Advantage. I truly company called Audio Eye. They offer a free website checker,
want business owners, content creators, site developers, etc., too. They will use it as a point of contact to try to sell you their
to understand that accessibility is in their best interest. They product, but I think most of us expect that these days.
should even see it as a competitive advantage as long as so I do want to give you some things to think about if you
little of the net is accessible. are going to use an automated checker or a site automation
However, it goes even further than Beth mentioned in her option. First, don’t trust any of them that promise 100%
previous article regarding GAAD. You see, it’s not just the one accessibility and remediation. Because even with generative
billion people with a disability, which is a market no one can AI, that promise just isn’t realistic. Second, you want to use
afford to ignore. But that doesn’t take into account the total an option that has been created with input from people repre-
reach of the disability community. Because we are a highly senting a wide variety of disabilities. And you want to see that
loyal consumer base, we will advocate for businesses and they are continuing to draw on experience from an actual live
brands that make an effort to make us feel welcome. I like testing group.
to say that designing to include disabled people is like hiring I love Beth’s suggestion of adding people with disabilities
influencers you won’t have to pay. When we find a company to your testing system. I would also encourage you to add
that provides a quality product or service in an accessible them to your design and customer service teams if you don’t
manner, we want everyone to know. We will talk to our already have them. This is because I have heard from coders
friends, family, coworkers, and social networks. Heck, we will about how challenging it is to turn out an accessible site when
even tell people we don’t like. the designers of the content aren’t familiar enough with the
But even that doesn’t completely cover the advantages of challenges of accessibility when creating images, audio, videos,
building in accessibility. Many of the problems that frustrate text documents, etc. Additionally, quite often, the first people
a user who is blind, hearing impaired, or physically disabled to know about an accessibility issue will be your customer
also cause problems for an able-bodied user. Many things support team. If they have at least a basic understanding of
that frustrate someone with a neurological or developmental accessibility, then they would know when and how to forward
disability make things harder for someone with no mental or these concerns so they get addressed.
emotional issues. In short, when you design inclusive prod- If your company has an internal learning and education
ucts, services, and content, you make your offerings better for program, consider inviting people with disabilities to become
everyone. part of your speaker team. Next, Beth mentioned sharing
These more enjoyable experiences will lead to loyalty about the accessibility improvements that you have already
whether the visitor is disabled or not. And this applies to made instead of talking about what you plan to do. I couldn’t
content as well. One way to grow the audience of a YouTube agree with this more. In my experience, companies are reluc-
channel, podcast, or live-streaming event is to make it inclusive. tant to talk about the work they have done and are doing. This
This would include offering things like alt text descriptions, is important because accessibility is one of those things you
closed captioning, text transcripts, and audio descriptions for have to continue to work at. I want to encourage you to write
both video and audio presentations. Heck, this inclusion can a blog post or record some other type of content chronicling
even lead to building stronger, more creative, resilient, and your investment in accessibility. You may even want to have
positive teams in the first place. someone from your team start appearing on podcasts that
reach the disability community to promote your efforts along
with your business and to solicit even more suggestions on
1 https://phpa.me/finally-03-2024
how to make your products, services, and content even more Once you have addressed a couple of items on the site eval-
inclusive. uation report, run it again. You will see how well your efforts
I’m currently looking for business leaders who have are working, and you can select a couple more items to work
embraced accessibility to come on my new podcast called The on. Many people like me understand just how challenging
Accessibility Advantage. And I look forward to discussing the accessibility is for a site owner or developer. As someone who
challenges they had to overcome internally and externally had to hand-code his site for several years before switching to
and how they managed to become more inclusive. I also look WordPress, I understand how hard this can be. And my sites
forward to hearing about how making the effort affected their were never accessible.
teams. For example, I have already heard from the owner of There are so many disabilities, and they use a wide variety
a small company who said that investing in accessibility and of adaptive technology. You also have to design for multiple
inclusion gave them a hiring advantage when competing for operating systems, platforms, and browsers. This is actually
younger, more socially motivated workers. part of why we give so much love to companies willing to
Wrapping up, I want to agree with Beth about taking make the effort. If there is some way I can help you get started,
action. She asked the community to do a couple of small, please reach out to me through the comments page or my
simple things. This is important because many people get website in my bio. Whether you need technical advice or
overwhelmed by what it takes to make their websites, apps, simply want some emotional reassurance, I want to be there
and content accessible. So, I want you to know that this will for you.
be a process. You won’t be able to implement everything at Because you see, The PHP Architect team does get it. They
once. And you shouldn’t. Most people, like me, appreciate brought me on to the team; I have a responsibility to do what
sincere, consistent effort over immediate compliance with I can to help each and every one of you implement accessi-
the minimum of the available arbitrary rule. Start by doing bility in whatever way and at whatever pace you are able to.
the hard things first. I like to say that it is easier for me to answer an awkward
I hope I have helped you realize the value of being inclusive. question than it is to make people guess. So, if you have a
So, step one for me is to accept that accessibility is a necessity, question about anything, please just ask. I want to see GAAD,
not a luxury. Then focus on the most important thing for your Global Accessibility Awareness Day, become a day of celebra-
business. If making a sale is the goal, then make it easy for us tion. Like Beth said, let’s make it a day where people share
to locate the relevant information and make a quick, smooth about the improvements they have made.
purchase with minimum distraction that gives us maximum
confidence in our buying decisions. Then, run a site review Maxwell Ivey is known around the world as
on Waves or a similar site. The Blind Blogger. He has gone from failed
Take a snapshot or screen share of where you stand right carnival owner to respected amusement
now. Then, select one or two things to start working on now. equipment broker to award-winning author,
motivational speaker, online media publicist,
A simple one to start with would be making sure that all
and host of the What’s Your Excuse podcast.
buttons and links are clearly labeled with text characters for
@maxwellivey
easy navigation by screen readers. Another might be adding
compelling, informative alt text to your images. Next, you
might modify the headings on your site so they can be easily
navigated. I will write more on that in a future article.
spinning the propeller to start the county fairs. Would they like a barn- Mom (Minta). Not once does the book
engine, there won’t be enough time to stormer to perform? mention that Glenn had a sister, Della.
scramble back onto the plane and take This was 1910. Everybody wanted to That seems odd. Was the author so
control. see a flyer perform. Minta’s idea was focused on Glenn that he simply acted
The plane nosed over, ending Martin’s brilliant. as if the sister did not exist?
first experience with building an aero- As part of his barnstorming act, This question, in my view, is another
plane. Martin would stake a handkerchief key to debugging software. If there’s a
Roy, Charlie, and Glenn sat down in full view of everyone in front of symptom, event, or circumstance that
at the kitchen table to design another the grandstand. Martin then took off, doesn’t fit the solution or seems out of
aeroplane. Martin wrote to Wilbur flying the biplane he had built in his place, this might mean you’ve not yet
and Orville Wright, sending drawings trademark black flying suit and leather found the solution.
of what they wanted to build (an aero- helmet. The answer is sad. Caltech explains in
plane). He asked the Wrights if they had At the end of each performance, “Accelerating Mental Health Research”6:
any objection to building that aeroplane. he switched off his airplane engine,
The Wrights received many such indicating trouble. This was after any Della Martin was 28 years old
letters during that time period. They number of dives and swoops and when her family had her commit-
were embroiled in patent fights with various acrobatic performances. With ted to the California Department
Glenn Curtiss. But Orville wrote back, the engine off, he dead-sticked in for of State Hospitals for hearing the
saying they had no objection to Glenn his “emergency” landing. He carefully, voice of God… she was 73 when
Martin building an aeroplane similar delicately landed, safe on the ground– her brother, aviation pioneer
to the drawings. Martin was duly with one wheel resting squarely on the Glenn Martin, died and she was
impressed to hear back. handkerchief. It was all part of the act! freed from institutionalization.
In Los Angeles, circa 1909-1910, That’s how the Glenn L. Martin She received an inheritance from
they built themselves an aeroplane. company came to exist, run by one of Glenn’s estate and, in her last 17
Beall built an engine for it with a light- the original barnstormers. His aircraft years of life, lived with a compan-
er-weight crankcase. The only space plant manager was the original barn- ion in San Marino and traveled
they could find that was large enough stormer (and likely taught Martin that the world. Before passing away, she
was a church building–so they built the bit with the handkerchief). dedicated her wealth to the forma-
aeroplane inside the church. They had Glenn Martin taught lumber magnate tion of a foundation to support
to remove (and replace) the entire front William Boeing to fly and sold him a mental health research.
of the church to get the aeroplane out! Martin airplane to take back home to
That aeroplane flew. By this point, Seattle. Boeing eventually crashed that
Martin’s mother, Minta, was a key plane in Lake Union. Boeing decided
partner in the success. he’d rather build his own plane than The Boy Engineer
Martin was a brilliant self-taught repair Martin’s. One of the Boeing I’ve mentioned Charles Day, who
pilot. He earned Expert Aviator Certif- company histories has a picture of the invented the laminated-wood propeller,
icate number two. (Glenn Curtiss had crashed plane that led to the founding and William Boeing, who built
earned number one.) But he wanted to of Boeing Aircraft, but it does not airplanes. I’m about to mention several
build airplanes. (In U.S. English, “aero- mention Glenn Martin, who built that other luminaries connected with Glenn
plane” became “airplane” circa 19164.) plane. Martin. They help answer our investiga-
To build airplanes, Martin needed a That minor omission turned out to be tion of “how we got here”.
factory. He needed funding. He went a key revelation for me. Two different Silent-screen actress Mary Pickford’s
barnstorming. It was a way to pick up narratives about the same business foundation explains Martin’s adven-
a few dollars here and there. He deliv- process might not look the same at all. ture in the 1915 Pickford film A Girl of
ered newspapers (in a bundle) by air, Or one might omit a key piece of infor- Yesterday7:
strapped to the wing of his biplane. mation that you’d never know unless
In short, Martin needed startup you went to an extra source. The plot of A Girl of Yesterday
funding and lots of it. As another example, Glenn Martin’s included a scene where Mary is
biography To Ride the Wind describes
5 kidnapped and taken away by
airplane that was to be filmed in
Crowd Funding scenes as a young boy, including
building things in the kitchen with
Minta Martin had an idea. They 6 Advancement and Alumni Relations.
found contacts for many California “Accelerating Mental Health Research,” October
5 Still, Henry. To Ride the Wind: A Biog-
events, up and down the coast, such as raphy of Glenn L. Martin. New York: Julian 10, 2023. https://phpa.me/mental-health-re-
Messner, Inc., 1964. https://phpa.me/oclc-en- search.
4 https://phpa.me/airplane-spelling tity. 7 https://phpa.me/girl-of-yesterday
Griffith Park… Mary stepped forward to be bound and Martin looked up, saying, “I am Mr. Glenn L. Martin. But I
gagged as the script called for, and she was placed in the haven’t time to talk right now, young fellow. Sorry, I’m waiting
small, four-seater plane… Mary’s pilot was a local aviator, for someone. Come out to my plant later on.”
Glenn Martin… Flying a plane was an everyday occur- I should note that this version of the story comes from
rence to Martin, but he balked at being in the film when the young man’s biography. The Martin biography tells a
he was told his role called for him to kiss a girl because somewhat different story. Both sources are printed books,
“My mother wouldn’t like it.” authoritative, peer-reviewed, and published during or shortly
after those persons’ lifetimes.
I found time and time again that I didn’t dare rely on a single
Figure 1 shows Glenn Martin (center) in front of his Model
source for anything, no matter how authoritative. When I dug
TT biplane, Mary Pickford on the right. The Model TT was
more deeply, I found surprises and contradictions. Always
a military trainer plane with two cockpits and dual controls.
consider the possible agendas, filtering, bias, and misunder-
Martin built three Model T and fourteen Model TT. The
standing. It happens.
earlier Martin T was delivered without engines, so the Army
The young man retreated hastily and took a seat across the
could put in whatever engine they wanted. The T/TT order
lobby. But he watched Martin, who was visibly anxious for his
was a huge order for Martin’s company.
man to arrive. Finally, the young man left his seat to approach
Martin again.
Figure 1.
“I don’t want to disturb you, Mr. Martin, but I think you’re
waiting for me.”
“You?” Martin laughed. “Son, if you must know, I’m
waiting for the Chief Engineer for my airplane factory, not
a high school boy.” Martin grinned. “Now, son, if your name
happened to be Donald Douglas–” Martin got no further as
his sentence was interrupted.
“My name is Donald W. Douglas.”
Martin stared in amazement and said, startled, “You. Why
you’re just a boy. A boy engineer!”
That’s how, according to Douglas company legend, Donald
Douglas became known at Glenn Martin’s aircraft factory as
The Boy Engineer. The famed Martin Bomber, the MB-1, was
actually designed by his Chief Engineer, Donald Douglas.
During World War II, Douglas Aircraft Company set up a
factory near Chicago to build a military transport airplane,
the C-54 Skymaster, at Orchard Place9. An airplane factory
needed a runway for departures, naturally, and the area
became known as Orchard Place / Douglas Field, ORD. After
the war, Chicago bought the property for one dollar and built
the airport known as O’Hare International (ORD).
When Donald Douglas was hired, the plant manager was
By 1915, World War I was raging, but the isolationist
Larry Bell. His Bell Aircraft Company10 later built the Bell X-1,
U.S.A. didn’t care. Glenn Martin’s chief engineer was Charles
the first airplane to break the sound barrier in level flight. You
F. Willard8, himself an aviation pioneer credited with several
might remember the Bell helicopters featured in the TV series
firsts. Willard left the Glenn L. Martin Company to join the
MASH.
U.S. Army Signal Corps. That was the part of the Army that
General Billy Mitchell, in the 1920s, famously sank some of
handled aviation (balloons and observing). This meant Martin
the U.S. Navy’s battleships as a demonstration. (A key feature
needed a new Chief Engineer. Martin considered carefully,
of Mitchell’s demos was that they worked.) General Mitchell
and there was someone interesting on the East Coast.
used the Martin Bomber for sinking naval vessels. The Martin
Martin invited this person (this was before email) to come
MB-2 Bomber was a Donald Douglas design with help from
out to Los Angeles and join Martin’s company. They arranged
someone named Dutch Kindelberger.
to meet in the Biltmore Hotel lobby in August 1915.
Dutch Kindelberger, when he later worked for Donald
As Martin sat in the lobby, a young man came in, approached,
Douglas at Douglas Aircraft, designed the earliest of the
and said, “You’re Mr. Glenn L. Martin?”
Douglas Commercial (“DC”) aircraft (DC-1, DC-2, DC-3,
9 https://www.phpa.me/orchard
8 https://www.earlyaviators.com/ewillard.htm 10 https://en.wikipedia.org/wiki/Bell_Aircraft
DC-4, …, DC-10). The C-54 Skymaster, noted above with that Martin served as an incubator. That’s a strong influence
Chicago O’Hare, was the military version of the DC-4. to consider.
Dutch Kindelberger left Douglas Aircraft Company to However, there’s one more piece to the puzzle: Martin
become president of North American Aviation. He brought himself. He had a rough Monday morning in 1918.
with him Lee Atwood, later known as the Dean of Aero-
space. Kindelberger and Atwood designed the B-25 bomber
(including Minnesota’s “Miss Mitchell”). Kindelberger named
Glenn Martin’s Monday Morning
their B-25 design the “Mitchell” in honor of the late General Circa 1916, Glenn Martin merged with the Wright Brothers
Billy Mitchell. This was, I believe, the only U.S. aircraft series to form Wright-Martin Aircraft Corporation. That sounded
named after a person. great but was horrible. The company hired a cement maker
Figure 2 shows the North American Aviation11 logo on as plant manager. They didn’t build airplanes, just Wright
my back-seat rudder pedal while flying at 2500 feet. Figure Cyclone airplane engines.
3 looks down at the airport ramp (parking area) as we break Figure 4 (on the next page) shows one of Miss Mitchell’s
hard left to circle and land. At the upper right of the ramp, two Wright Cyclone engines. We had just backed the airplane
the larger silver plane, is our North American B-25 “Miss into the hangar after her first public flight of 2023 (and my
Mitchell”. At lower right, with yellow wings and blue fuselage, first ride in back). Our maintenance crew was awaiting our
is our Vultee Valiant, known as the “Vultee Vibrator” because return and took over immediately.
of what it did to the building windows when it flew by. Both I’m a text person rather than a visual person. However, it
the blue Valiant and the one I’m riding, our yellow North sure makes a difference when I can see and touch the subject
American SNJ-6 Texan, were used for pilot training during at hand. A picture or screenshot can make many things
World War II. clear. Watching a subject-matter expert at work can be most
We’ve now answered, “How we got here”. Much of the story enlightening.
revolves around Glenn Martin. This might mean aviation was Back in 1916, neither Martin nor the Wrights were happy.
a very small world at the time (it was), but it could also mean That company dissolved within ten months. It had been in
New York. Returning to his factory in Los Angeles, Martin
Figure 2. realized he needed to expand. He was disgusted with the year
wasted not building airplanes. (I can relate, but I’m certainly
not at Martin’s level!)
Martin spoke with the owner of the Cleveland Indians
baseball team, Alva Bradley. Bradley and Martin created a
combined interested in building aircraft for war, but there
was a catch. The combine wanted the airplanes to be built in
Cleveland.
This meant building a new factory. Martin saw this as
fantastic. Greenfield development (i.e., building a new
factory) would allow him to implement various manufac-
turing ideas he’d pioneered in Los Angeles.
Figure 3.
11 https://phpa.me/na-aviation
Summary
I told part of the Glenn L. Martin story. He influenced, hired,
or taught to fly several aviation pioneers. However, the reason
for the story is that it’s a “people” story. It’s worth studying
the choices made. Learning how people influence and make
choices provides useful insight for software development.
There’s no substitute for seeing, touching, and hearing. It
was enlightening to observe that when a Wright Cyclone
starts up (Figure 5), everyone looks. Seeing people react
provides insight you won’t have otherwise. Next time you do
a demo, watch for the reactions–or non-reactions.
Figure 5.
© Perforce Software. All trademarks and registered trademarks are the property of their respective owners.
RADAR
Golang is fast, but Rust outperforms it due to its fine control over
Created by Google, the Go language (popularly known as system resources. Rust’s primary differentiator is its focus
Golang) is a statically typed, compiled language known for its on memory safety while maintaining high performance.
simplicity and effectiveness. Its primary appeal is its straight- Its built-in memory management technique makes it safer
forward syntax, which makes it relatively easier to learn and without relying on garbage collection, as Golang does.
use, even for beginners. Golang shines in enabling concur- Golang has a strong edge over Rust in terms of concurrency.
rent programming and managing extensive programs. It’s It simplifies concurrent programming through goroutines
widely used in system and network programming, big data, and channels, making deploying and scaling large distributed
and cloud services. systems easier. Golang is generally easier to learn and use,
especially for PHP developers. Its syntax and conventions are
Rust more intuitive and reminiscent of common languages like
Conversely, Rust1 is a multi-paradigm programming JavaScript and Python. Both languages offer powerful tools
language focused on performance and safety, specifically safe to ensure code is well-written and bug-free. However, Rust’s
concurrency. Developed by Mozilla, Rust eliminates common steep learning curve might slightly set PHP developers back.
programming errors by implementing a strong compile-time So, Which Language Should PHP Developers Learn?
checking system. Rust features zero-cost abstractions, guar- If you prioritize simplicity and ease of learning and need to
anteed memory safety, and a rich-type system renowned in handle heavy network tasks or microservices, Golang is your
system programming, particularly where high performance go-to language. Its similarity to PHP in terms of syntax can
and safety are required. make it more of a seamless transition.
Rust would be a better fit for developers interested in
PHP system-level programming and working environments that
Given the title of this magazine, I shouldn’t have to write focus on memory safety and performance. It might initially
this, but let’s make sure we cover some bases. PHP is a widely seem complex, but its safety guarantees are unparalleled.
used open-source scripting language suitable for web devel-
opment. PHP is reasonably versatile and compatible with Performance Comparison
most infrastructure systems used today. It was first released Rust and Golang are both compiled languages known for
in 1994 by Rasmus Lerdorf and has since evolved with many their outstanding performance. Rust’s zero-cost abstractions
version updates, focusing on improved performance, power system, ownership model, and strong static typing enable it to
and syntax enhancements, and some types. However, some excel in system-level programming tasks. On the other hand,
communities have tried to get PHP into a more platform-ver- Golang’s simplicity and efficient concurrency model make it
satile state, expecting it to become a standard tool for desktop ideal for creating highly scalable services.
applications or otherwise; it is not likely to gain much trac- For PHP developers, Rust provides an opportunity to build
tion in a JavaScript-dominant world. performance-critical sections of the application with signifi-
Because of a few areas of modern cloud infrastructure that cantly higher speed. Golang, with its inherent simplicity,
are not easily PHP compatible, many PHP developers look to permits the smooth running of programs with large amounts
different languages. Some will jump to Node because it feels of concurrent processing, a significant advantage in modern
as natural as writing more powerful JavaScript. But others are web development.
left pondering: Should I try Golang or Rust?
Both of these languages deliver excellent performance, but
they approach execution times differently. Golang’s runtime
1 https://rustforphp.dev
Memory Safety which language to learn next should align with your career
Memory management is a significant challenge in system path, project needs, and personal interests. Regardless of the
programming. Rust shines here with its zero-cost abstrac- choice, discovering a new language is an exciting journey that
tions, guaranteeing memory safety without using garbage broadens understanding, improves problem-solving, and
collection. It allows you to manage memory efficiently with opens new opportunities in terms of jobs and how you can
advanced features like ownership, borrowing, and lifetimes. impact the community.
On the other hand, Golang uses garbage collection, One more thing
relieving developers from worrying about memory manage-
Within the PHP community, some lovely courses are avail-
ment. While it does provide simplicity and convenience, it
able for those who wish to adopt a new language for more
lacks the fine control and zero-cost abstractions of Rust.
high-performance components. Ryan Chandler has a course
Ease of Use on Rust, and Mohammad Said has one on Golang2. Both of
Golang is often considered to be easier to pick up and use these developers highlight the point that Rust and Golang are
from a PHP developer’s perspective. It maintains a straight- more optimal as extensions of a PHP-based application rather
forward approach to programming with clear syntax, which than a complete replacement. Handing complex processes
resembles that of PHP. Rust, with its unique concepts like to a Rust or Golang micro-service can help optimize a PHP
ownership and lifetimes, may present a steeper learning application without overhauling the whole system.
curve for PHP developers. If you’re interested in courses that can help a PHP devel-
oper adopt either of these languages, I strongly recommend
Concurrency looking at them. Ryan and Mohammad have been strong
Concurrency in Golang is a first-class citizen. It’s built into figures in the Laravel community and are highly skilled at
the language via goroutines and channels, making it easy developing scalable systems and teaching complex topics in
for PHP developers to build incredibly fast applications that an easy-to-understand manner.
handle multiple processes at once.
Rust also supports concurrency but offers a different level Matt has been developing software for over
of convenience than Golang. The ergonomic syntax in Golang 13 years. He started his career as a PHP
makes concurrent programming easier and safer, providing developer for a small marketing firm but
another reason why PHP developers might want to consider has since worked with a few Fortune 500
companies, led a couple teams of developers,
this language.
and is currently a Cloud Architect for a
Documentation and Community Support significant Travel technology company. He’s
contributed to the open-source community
Both Rust and Golang have extensive documentation and on projects such as Cordova and Laravel.
are supported by active communities. However, Golang, He also made numerous packages and has
being older and backed by Google, has a larger ecosystem and helped maintain a few. He’s worked with
arguably better support for web development. start-ups and sub-teams of big teams within
Both Golang and Rust present extensive capabilities for large divisions of companies. He spends
PHP developers looking to expand their programming time with his wife and kids when he’s not
skills. As I’ve said, these languages are not meant to replace tinkering with code or learning new technol-
PHP but aim to offer alternative approaches to solving ogies. @Mattylantz
modern programming challenges. Ultimately, deciding
2 https://themsaid.com/courses/php-to-go
Spaghetti code gets its name from the tangled branching arguments to the method call. Does this sound like a lot of
paths, large lines of nearly identical, copy-pasted blocks, potentially needless extra work? It might be, but we can use
which make it nearly impossible to understand a program a dependency injection container to centralize and manage
flow. It’s a rich source for bugs, often due to small changes object creation.
having an unintended (or unpredictable) effect elsewhere. Of
course, this is not a problem specific to PHP code. It’s why
nearly all programming languages support user-defined func-
An Example
tions, classes, and objects. CPUs don’t need all that syntactic Consider a typical—though slightly contrived—example
sugar; machine code is good enough for them. We need our function that’s going to read one or more rows from a data-
programming languages to aid us so that we can reason about, base and output them to a webpage (see Listing 1). It gets
understand, and maintain the code. the job done, but it’s highly coupled. It needs to know how
PHP 8’s object model has matured tremendously since the to connect to the database and relies on three constants that
rudimentary object-oriented support introduced by PHP must be defined globally. The output is hardcoded to immedi-
4. Using classes with well-named methods and properties ately echo an HTML table, with one record per row.
goes a long way to making our code readable and limiting
how much we need to comment it. Dependency Injection is
another useful tool to master and add to our belt. Listing 1.
1. <?php
Dependency Injection 2.
3. function showRecords(int $max): void
Object-oriented programming aims to organize code into 4. {
reusable chunks of related code, but often, many classes 5. $pdo = new PDO(DB_DSN, DB_USER, DB_PASSWORD, [
are filled with long lines of procedural code hidden behind 6. PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ
method calls. We want to use small classes with limited 7. ]);
8.
scopes that we can put together when we need to add a new
9. $stmt = $pdo->query(
feature or fix a bug. To put it another way, any class should
10. 'SELECT title, author, genre, pages, year
be more than happy to delegate as much of its work to other 11. FROM `books` LIMIT ' . $max
specialized objects. 12. );
Dependency injection is easy to describe and harder to 13.
adhere to in practice. A dependency is an instance of a class 14. echo '<table>';
in which our program needs to function. It can be a class 15. while ($row = $stmt->fetch()) {
that handles access to the database layer, a client for making 16. echo sprintf(
calls to an external API, or something that takes one or more 17. '<tr><td>%s</td><td>%s</td><td>%s</td>'.
18. '<td>%d</td><td>%d</td></tr>',
inputs and renders them as HTML, CSV, or some other
19. $row->title,
output format. 20. $row->author,
The function or method that needs a dependency should 21. $row->genre,
not be created using the new keyword, which may require 22. $row->pages,
knowing how to create the dependency’s dependencies. They 23. $row->year
should already be available when we need them. To do so, 24. );
we inject the dependencies — which is just a fancy way of 25. }
saying we pass them either as constructor arguments or as 26. echo '</table>';
27. }
Let’s consider the main tasks we’re asking our function to kind of “Renderer” we pass to showRecords(), as you can see
perform. First, we’re querying a database table named books on Listing 3. First, we defined an interface to specify how
to get some number up to $max results. Then, we create a any ResultRenderer must work. By doing so, no matter what
simple HTML table for each row returned. Those sound concrete implementation we pass as showRecords() as the
like two separate concerns: reading from the database and $output parameter, showRecords() knows how to use it. All
creating the HTML output, which we could inject when we showRecords() cares about is that there’s a render() method
call showRecords. that takes our database query results. The implementation
Listing 2 updates showRecords so that it takes two additional details of outputting a CSV file are handled by a new class,
arguments. This is how we inject our dependencies. The first
is the PDO connection object used to query the database, Listing 3.
followed by a new class, HTMLBookTableOutput, that renders
1. <?php
2.
Listing 2. 3. interface ResultRenderer {
4. public function render(PDOStatement $stmt): string;
1. <?php
5. }
2. class HTMLBookTableOutput 6.
3. { 7. class CSVBookOutput implements ResultRenderer
4. public function render(PDOStatement $stmt): string 8. {
5. { 9. private $fh;
6. $out = '<table>'; 10.
7. while ($row = $stmt->fetch()) { 11. public function __construct(public string $filepath)
8. $out .= sprintf( 12. {
9. '<tr><td>%s</td><td>%s</td><td>%s</td>' 13. $this->fh = fopen($filepath, 'w');
10. . '<td>%d</td><td>%d</td></tr>', 14. }
11. $row->title, 15. public function render(PDOStatement $stmt): string
12. $row->author, 16. {
13. $row->genre, 17. while ($row = $stmt->fetch()) {
14. $row->pages, 18. fputcsv($this->fh, (array) $row);
15. $row->year 19. }
16. ); 20.
17. } 21. fclose($this->fh);
18. 22.
19. $out .= '</table>'; 23. return file_get_contents($this->filepath);
20. return $out; 24. }
21. } 25. }
22. } 26.
23. 27. function showRecords(
24. function showRecords( 28. int $max, \PDO $pdo, ResultRenderer $output
25. int $max, \PDO $pdo, HTMLBookOutput $output 29. ): string {
26. ): string { 30. $stmt = $pdo->query(
27. $stmt = $pdo->query( 31. 'SELECT title, author, genre, pages, year
28. 'SELECT title, author, genre, pages, year 32. FROM `books` LIMIT ' . $max
29. FROM `books` LIMIT ' . $max 33. );
30. ); 34.
31. 35. return $output->render($stmt);
32. return $output->render($stmt); 36. }
33. } 37.
34. 38. // these constants still come from somewhere external
35. // these constants still come from somewhere external 39. $pdo = new PDO(DB_DSN, DB_USER, DB_PASSWORD, [
36. $pdo = new PDO(DB_DSN, DB_USER, DB_PASSWORD, [ 40. PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ
37. PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ 41. ]);
38. ]); 42.
39. showRecord(20, $pdo, new HTMLBookTableOutput()); 43. $output = new CSVBookOutput(__DIR__ .'/example.csv');
44. showRecord(20, $pdo, $output);
the HTML table. As a result, showRecords() is just 6 lines CSVBookOutput. Note that in both listings, showRecords doesn’t
compared to twenty. change at all.
What did that buy us? Consider a new request to show $max A further refinement to showRecords() could be to define an
number of books as a CSV file. We need only change what interface for classes that retrieve books from any number of
sources—databases, document stores, external APIs, or local instances and use reflection or a custom call to instantiate any
files. We’d need to change how a renderer works, but it’s not object we need.
Since this is a common component across frameworks,
Listing 4. the PHP-FIG has defined PSR-11: Container Interface1 to
“standardize how frameworks and libraries make use of a
1. <?php
2.
container to obtain objects and parameters”. This gives us a
3. interface BookRepository { number of solutions we can use depending on our framework
4. /** and preferences:
5. * @return BookRecord[] • Symfony’s DependencyInjection Component2
6. */
7. public function retrieve(int $max): array; • The PHP League’s Container3
8. } • The succinctly named PHP-DI4
9.
10. interface ResultRenderer {
11. /** Storing Sensitive Information
12. * @return BookRecord[] $books
When we register our new account with SpaceTraders, the
13. */
14. public function render(array $books): string; response it returns includes a bearer token we must save and
15. } use to authenticate future requests. Since whoever knows that
16. token can act on our behalf, we want to save it somewhere
17. function showRecords( safe. Certainly, we should never commit secrets into a git
18. int $max, repository. While convenient, it is not a secure practice. Once
19. BookRepository $repo, you’ve committed a secret to your version control’s history,
20. ResultRenderer $output removing it may be difficult or impossible. If your code leaks
21. ): string {
or is public, then anyone has it.
22. $books = $repo->retrieve($max);
23. return $output->render($books); One more thing: if you need to use different secrets for
24. } testing, sandbox environments, or independent installs,
saving your database passwords or API tokens alongside
your code couples it to those environments. Think of it this
way—your code shouldn’t know that you have a local envi-
a huge leap from what we have so far. I’ve sketched out the ronment, a testing one, a staging one, or even a production
interfaces and typehints in Listing 4. environment. Your code just needs to know how to connect
to one of them via common configuration settings like URLs
and credentials.
Tips for Success Luckily for us, we have vlucas/phpdotenv5, which reads
Using dependency injection takes effort when you’re used secrets from .env files and makes them available via the $ENV
to making the objects you need where and when you need super global. Their readme walks through the basic steps for
them, but it pays dividends quickly. Keep these things in mind. adding it to a project:
• Use interfaces to define the injected dependencies. This 1. Install it: composer require vlucas/phpdotenv
decouples your code, though you can get away with 2. Create a .env file and add a line for it to .gitignore
specifying a concrete class if it will never change. 3. Create a .env.example file for sharing stubs so anyone
• Objects never create other objects (unless they’re using your project knows what secrets they will need.
a factory). Try to always pass in a dependency as a
constructor argument, preferably as a method argument. Our initial .env.example file is one line, but we’ll likely add
• Classes shouldn’t inspect global variables, superglo- more as the project grows.
bals, or other bits of external state to influence how they # token value from registering a spacetraders callsign
behave. SPACETRADERS_TOKEN=""
Containers
The example earlier has very few dependencies that I
manually tracked and created. In practice, we wouldn’t want 1 https://www.php-fig.org/psr/psr-11/
to create the same dependencies every time we need one 2 https://phpa.me/symfony-di
throughout our code. Dependency injection containers help 3 https://container.thephpleague.com
us manage this task by centralizing how we request object 4 https://php-di.org
5 https://github.com/vlucas/phpdotenv
I then updated the spacetraders CLI app to load the values Once we have an account register, other commands should
from .env by adding these two lines after Composer’s auto- interact with the API through a $client instance. For example,
loader: to read information about our “Agent” in spacetraders, I
added another CLI command for it that calls a new method
require __DIR__ . '/vendor/autoload.php';
Instead of having all those cURL lines in our controller, we named myAgent(). Listing 6 outlines such a class. Notice that
want to have thin commands that call the service classes that our constructor specifies two dependencies that we need
do the real work. The command should take care of any input to function: a $token, if we have one, and any instance of a
validation and then call something like: guzzle client. We’re not hardcoding how Guzzle behaves, if it
follows redirects, how long it waits for timeouts, etc., within
$client = new Phparch\SpaceTraders\Client($token); the Spacetraders client. All the client cares about is, “Give me
$response = $client->register($symbol, $faction); a guzzle object that I know how to use”.
6 https://www.github.com/guzzle/guzzle
Beth Tucker Long is a developer and owner at Treeline Design, a web development company, and runs Exploricon, a
gaming convention, along with her husband, Chris. She leads the Madison Web Design & Development and Full Stack
Madison user groups. You can find her on her blog (http://www.alittleofboth.com) or on Twitter @e3BethT