<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: SyntaxSeed (Sherri W)</title>
    <description>The latest articles on DEV Community by SyntaxSeed (Sherri W) (@syntaxseed).</description>
    <link>https://dev.to/syntaxseed</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F146027%2F1b4a6700-5bb2-46ca-86e1-74880593f31b.jpeg</url>
      <title>DEV Community: SyntaxSeed (Sherri W)</title>
      <link>https://dev.to/syntaxseed</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/syntaxseed"/>
    <language>en</language>
    <item>
      <title>RPG In A Box – A Game Dev Tool For Everyone</title>
      <dc:creator>SyntaxSeed (Sherri W)</dc:creator>
      <pubDate>Mon, 19 Dec 2022 23:37:17 +0000</pubDate>
      <link>https://dev.to/syntaxseed/rpg-in-a-box-a-game-dev-tool-for-everyone-2jeh</link>
      <guid>https://dev.to/syntaxseed/rpg-in-a-box-a-game-dev-tool-for-everyone-2jeh</guid>
      <description>&lt;p&gt;One recent evening, my husband grabbed my attention, to show me a newly free title on Epic Games, called RPG In A Box. On a brief read of the description I figured it sounds interesting, so he added it to his library so we can try it for free later.&lt;/p&gt;

&lt;p&gt;Fast forward about a week, and my oldest son -10 years old- starts excitedly telling me about a game that he’s making. With a shop, and different weapons based on which class you are going to be, that he’s building inside of… Minecraft. Now, this is not very unusual. He’s had a strong interest in making games for a couple years now. From printouts and leftover minis turned into board games – my favourites being "Don’t Wake Mom!" and "AmongUs Ants: Board Game Edition". To game authoring tools aimed at children like level editors in games like Mario Brothers and Battle Block Theatre, to more recently Game Builder Garage which we own on the Switch. He’s constantly building things in these tools. He even play tests and tweaks them repeatedly to get the balance just right.&lt;/p&gt;

&lt;p&gt;The downsides to these video game options, is that the games you create with them are trapped inside of those tools. To play one of his Game Builder Garage games, you must also own Game Builder Garage. As kid-friendly as these are, they are walled gardens and typically it’s just his brothers and us his parents who play his games. I also get the feeling that what he really wants to create is a bit beyond the scope of these tools. Custom quests and characters, big maps and the ability to tell a story.&lt;/p&gt;

&lt;p&gt;In comes &lt;a href="https://www.rpginabox.com/" rel="noopener noreferrer"&gt;RPG In A Box&lt;/a&gt;. It's a game development toolkit that is very approachable. You can write simple scripts with a visual editor or dive into the code to create more complexity. It comes with a variety of editors for maps, voxel models (voxels are like pixels but 3D), combat, sound effects, quests and more. Everything is layed out well in a nicely designed interface. Every menu option and tab has an icon next to it, which aids in the friendliness. There’s detailed in-app documentation, and a full demo game that you can load up and edit, to study how it works or to use as a starting point. You can even start a fresh game but import the assets from the demo game to get you rolling.&lt;/p&gt;

&lt;p&gt;The game lets you export your games for Windows, Linux and Mac computers, and you aren’t trapped in the RPG In a Box ecosystem. You are allowed to sell your games without royalties, and there is even a free demo version (which I started using from Steam on my Linux machine, to learn alongside my son) which has all the features, just a limited map size and a branded splash screen on exports.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1em1jevmbghi8k11qxr8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1em1jevmbghi8k11qxr8.png" alt="The RPG In A Box voxel editor – creating an astronaut."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My son and I have been at it for a little over a week. It’s all he wants to talk about and he’s been eagerly offering to do extra chores to earn additional computer time. We’ve been picking things up surprisingly quickly. And I’ve been quite pleased to discover that he’s been figuring out aspects of the tool that I haven’t even touch yet myself. For example he’s managed to get his game to trigger several turn-based fights with the combat editor, and we didn’t even watch a tutorial on that aspect of the tool. I really thought I’d have to help him a lot more, but he’s running with it.&lt;/p&gt;

&lt;p&gt;Which brings me to the one criticism I have so far. RPG In a Box is new to the scene. It released version 1.0 in May 2022. And its userbase seems small so far. As a result, the amount of user-generated content like tutorials, beginners’ guides, etc are very limited. There are only a few YouTubers who’ve created videos on how to use the application. The official RPG In A Box channel has a completely fantastic tutorial series on YouTube by the creator’s wife which are 100% perfect for beginners, but unfortunately they cover the voxel editor only. If you want to go beyond map and voxel model editing, and a bit of Bauxite (the scripting language) and the very basics, you’re out of luck. There is high-quality documentation in the app and on the website, but as of this writing it’s incomplete. For example, the online docs wiki refers in several pages to quests (there is a Quest editor in the game), but the &lt;a href="https://www.rpginabox.com/docs/doku.php?id=quest" rel="noopener noreferrer"&gt;quest page&lt;/a&gt; on the wiki is currently empty.&lt;/p&gt;

&lt;p&gt;It’s understandable that the rush to add new features is very real and it’s hard to justify time for documentation or tutorials when users are rabidly demanding the next feature or a critical bug fix. However in this stage of a tool’s lifetime, capturing those interested users who just need a bit of a hand-hold to really adopt your software is worth its time in gold. If I could make one suggestion to the creator, Justin, it would be to set aside a sprint or two to JUST work on documentation, and to definitely continue the tutorial series that Sarah started creating on YouTube. After the voxel editor, the tutorials don’t need to be quite so beginner friendly. A 20 minute overview of each tool in the software and also a video series on how the demo game was made, would be a great start. The game does have a very active Discord server and I’ve been receiving a lot of help there as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxb2l7ti5m1u7e52vwga0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxb2l7ti5m1u7e52vwga0.png" alt="RPG In A Box – Demo game screenshot."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To put my money where my mouth is so to speak, I will be creating a series of posts &lt;a href="https://blog.syntaxseed.com/" rel="noopener noreferrer"&gt;on my blog&lt;/a&gt; to cover tasks I’ve figured out how to do, and useful bauxite scripts I’ve written for common tasks in RPG In a Box. Hopefully helping to make it so when users google common, problems, they find RPG In a Box specific answers. 🙂&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt; I will absolutely be buying the full version soon, and probably creating a bunch of guides and maybe some YouTube tutorials myself. More documention and YouTube guides will come with time, because a tool this great and this approachable will gain passionate users like a magnet. If you’re looking for a friendly, useable game authoring tool, and especially if you’re looking for something you can use along with your older kids and teens, or for students in school, this is a great option for you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update, Dec 21:&lt;/strong&gt; Another several days of actively working with the tool, including one fun day without school where my son and I bascially spent all day working with it, and I have to revise my review a bit at least for myself. I work on a Ubuntu Linux development PC, and I don’t know whether the stability issues I’m encountering are related to my environment, or RPG In a Box… however, I encounter game crashes very frequently (when I Quick Play my games, not of the application itself). I can’t add a real-time attackable NPC to the game because encountering the character crashes it. Even the demo game that comes with the software, crashes at a very specific point in the game when played. &lt;/p&gt;

&lt;p&gt;I’ve reported a few bugs in the official Discord channel and the creator kindly reached out to say he's going to temporarily remove the offical 'supported on Linux' state and revisit in the future. Since these are pretty much show-stoppers, I’ll have to shelve the tool for now and try it again after a few more updates. I’ll definitely be coming back in the future.&lt;/p&gt;

&lt;p&gt;All that said however, my son who is using it on a Windows 10 machine, has encountered none of these issues, and his game he’s been working on has been coming along fantastically.&lt;/p&gt;

&lt;p&gt;TL;DR – If you’re on a Linux pc, I recommend trying the free demo first, and make sure you can play all the way through the demonstration game that’s included.&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
&lt;a href="https://blog.syntaxseed.com/rpg-in-a-box-a-game-dev-tool-for-everyone/" rel="noopener noreferrer"&gt;Originally Published on Blog.SyntaxSeed.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>rpginabox</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Learn PHP For Experienced Developers</title>
      <dc:creator>SyntaxSeed (Sherri W)</dc:creator>
      <pubDate>Mon, 11 Jan 2021 16:12:27 +0000</pubDate>
      <link>https://dev.to/syntaxseed/learn-php-for-experienced-developers-2347</link>
      <guid>https://dev.to/syntaxseed/learn-php-for-experienced-developers-2347</guid>
      <description>&lt;p&gt;In my efforts to help a colleague, I discovered that there are few resources for people who are &lt;strong&gt;already programmers in other languages&lt;/strong&gt; to learn PHP. Something that isn't beginner level, doesn't explain basic programming concepts... just get to the heart of &lt;strong&gt;what makes PHP unique&lt;/strong&gt;, and some suggested quality resources to learn more.&lt;/p&gt;

&lt;p&gt;This is what I've written here. It's a high-level overview of the language, and some vetted resources to get set up and learn more.&lt;/p&gt;

&lt;p&gt;Let's get started...&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Up A Local Dev Environment
&lt;/h2&gt;

&lt;p&gt;Even if you aren't going to be using a major framework like Symfony or Laravel... if you set up an environment that can run these frameworks, you'll have everything you'll likely need for most PHP development. These usually include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PHP – the language runtime&lt;/li&gt;
&lt;li&gt;MySQL – database&lt;/li&gt;
&lt;li&gt;NGINX or Apache – web server&lt;/li&gt;
&lt;li&gt;Composer – PHP's package manager&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Do you like VMs?&lt;/strong&gt; Use the excellent &lt;a href="https://laravel.com/docs/master/homestead" rel="noopener noreferrer"&gt;Vagrant box customized for PHP development called Homestead&lt;/a&gt;. (I have used this myself.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Like Docker?&lt;/strong&gt; Try:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://laradock.io/" rel="noopener noreferrer"&gt;https://laradock.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.digitalocean.com/community/tech_talks/how-to-create-php-developer-environments-with-docker-compose" rel="noopener noreferrer"&gt;https://www.digitalocean.com/community/tech_talks/how-to-create-php-developer-environments-with-docker-compose&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Have/want a local webserver?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.apachefriends.org/" rel="noopener noreferrer"&gt;XAMPP is one of the most popular solutions.&lt;/a&gt; It is a distribution of Apache with MariaDB &amp;amp; PHP included.&lt;/p&gt;

&lt;p&gt;If you already have Apache or NGINX installed locally and like to do local development without a virtual machine – you can install PHP and it's most popular extensions directly. These are the commands I use on Ubuntu (Linux) to install PHP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;add-apt-repository &lt;span class="nt"&gt;-y&lt;/span&gt; ppa:ondrej/php
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; php7.4 php7.4-common php7.4-cli php7.4-fpm libapache2-mod-php7.4 php-pear php7.4-bcmath php7.4-bz2 php7.4-curl php7.4-dev php7.4-gd php7.4-intl php-gettext php7.4-json php7.4-mbstring php7.4-mysql php7.4-opcache php7.4-readline php7.4-soap php7.4-sqlite3 php-xdebug php7.4-xml php7.4-xmlrpc php7.4-zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;On Windows, many developers use &lt;a href="https://www.wampserver.com/en/" rel="noopener noreferrer"&gt;WAMP&lt;/a&gt;. You can also install it directly using WSL (Windows Subsystem For Linux) or use the &lt;a href="https://www.php.net/manual/en/install.windows.php" rel="noopener noreferrer"&gt;Windows install guide in the official PHP manual&lt;/a&gt;. The move to WSL2 means Windows users can more or less follow Linux guides. &lt;a href="https://laragon.org/" rel="noopener noreferrer"&gt;Laragon&lt;/a&gt; is another dev environment for Windows.&lt;/p&gt;

&lt;p&gt;Users on Mac often use &lt;a href="https://www.mamp.info/" rel="noopener noreferrer"&gt;MAMP&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For myself, I work on a Ubuntu machine and I have PHP, MySQL &amp;amp; Apache installed directly.&lt;/p&gt;

&lt;p&gt;These are some excellent guides for setting up a local environment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Windows:&lt;/strong&gt; &lt;a href="https://netbeans.apache.org/kb/docs/php/configure-php-environment-windows.html" rel="noopener noreferrer"&gt;https://netbeans.apache.org/kb/docs/php/configure-php-environment-windows.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linux:&lt;/strong&gt; &lt;a href="https://netbeans.apache.org/kb/docs/php/configure-php-environment-ubuntu.html" rel="noopener noreferrer"&gt;https://netbeans.apache.org/kb/docs/php/configure-php-environment-ubuntu.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mac:&lt;/strong&gt; &lt;a href="https://netbeans.apache.org/kb/docs/php/configure-php-environment-mac-os.html" rel="noopener noreferrer"&gt;https://netbeans.apache.org/kb/docs/php/configure-php-environment-mac-os.html&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Try It Out
&lt;/h2&gt;

&lt;p&gt;You'll know you're ready to roll when you can run:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;on a command line and see the PHP version info.&lt;/p&gt;

&lt;p&gt;PHP has a built in command line interactive mode which lets you type and run PHP commands to try things out. Type:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It will give you a prompt where you can enter lines of PHP code and when you hit enter it will run those lines and show the output. If you like using something like this, I recommend the more advanced &lt;a href="https://psysh.org/" rel="noopener noreferrer"&gt;PsySH&lt;/a&gt; which does the same thing but much nicer.&lt;/p&gt;

&lt;p&gt;You can run a PHP file from the command line like so:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php index.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;PHP also has a built-in web server that you can use instead of having Apache or NGINX installed. This is nice for quick testing. In fact much of my development uses this built in web server and a local installation of MySQL. I have Apache but often don't need it. Run the built-in web server within a directory that has .php files like so:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php &lt;span class="nt"&gt;-S&lt;/span&gt; localhost:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This will start up the web server listening on the given host and port. Then if you visit &lt;strong&gt;&lt;a href="http://localhost:8000/" rel="noopener noreferrer"&gt;http://localhost:8000/&lt;/a&gt;&lt;/strong&gt; in your browser you can execute your PHP application that exists in that directory.&lt;/p&gt;

&lt;p&gt;Note that the index.php file is the entry point for most PHP applications. The URL above will call index.php by default.&lt;/p&gt;
&lt;h2&gt;
  
  
  PHP Language Overview
&lt;/h2&gt;

&lt;p&gt;PHP is an interpreted language meaning that your PHP programs are not compiled ahead of time. When a browser makes a request to a web server for a PHP resource (usually a .php file) the web server provides all the details of the request (for example the URL GET parameters, POST values, cookies, headers, etc) to the PHP interpreter which executes the requested PHP file. If you edit a PHP file on the server, that change will take place immediately.&lt;/p&gt;

&lt;p&gt;Most of the time the index.php file is the entry point to a PHP application and it usually performs some bootstrapping and executes the framework to handle the request values which are often packaged together into a Request object. Older applications might not use a Request object, in that case the values from the request can be found in &lt;code&gt;$_GET, $_POST, $_COOKIE, $_SERVER&lt;/code&gt; super global arrays which are accessible from anywhere in an application. Modern frameworks place these into a Request object then wipe out those super global values to prevent pitfalls of global variables.&lt;/p&gt;

&lt;p&gt;As the PHP program executes, the output is returned to the browser. Some programs send output in an ad hoc manner using &lt;code&gt;echo()&lt;/code&gt; statements and similar commands which send output to the standard output stream (back to the web server which sends it to the browser... or to the command line). Modern applications gather all output into a Response object which is sent to the browser all at once at the end of the program's execution (one of the framework's final steps).&lt;/p&gt;

&lt;p&gt;PHP is stateless by default. All variables, objects, and connections created when the program executes for a request, are not retained for the next request. PHP clears the memory used during that request and doesn't know anything between one request to the next. Multiple requests coming into a server can be executed concurrently.&lt;/p&gt;

&lt;p&gt;There are mechanisms that PHP developers use to maintain some memory or state between requests. The most common method is Sessions. PHP sends the browser a session ID value which is usually stored in a cookie. The browser sends back this ID with all future requests. PHP uses that ID to look up values stored on the filesystem or in a database (or a data store like Redis or Memcached) that are associated with that ID. In this way PHP can ‘remember' the visitor between requests. However these values in the Session storage must be read from the data store on every request. They are saved in a super global called $_SESSION which can be accessed from within the application. Many frameworks place this super global into their own Session object.&lt;/p&gt;

&lt;p&gt;This is a good article (&lt;a href="https://carlalexander.ca/php-application/" rel="noopener noreferrer"&gt;https://carlalexander.ca/php-application/&lt;/a&gt;) about how PHP works including topics about concurrency and multitasking in PHP.&lt;/p&gt;
&lt;h2&gt;
  
  
  Types In PHP
&lt;/h2&gt;

&lt;p&gt;PHP is a dynamic, weakly typed language. Variables are not defined with a type (and cannot be), instead the type is inferred by what is assigned to it and can change if something new is assigned.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$something&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Weakly typed as an integer.&lt;/span&gt;
&lt;span class="nv"&gt;$something&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Now it's a string.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This means that you will find a lot of type checking and casting in PHP programs:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;intval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$age&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Make sure $age is an integer.&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;is_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// Do something.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The above sorts of forcing and checking of types are very common in PHP applications. Since all values passed to PHP in the request from the browser are strings, PHP programs will often cast these values to the types expected.&lt;/p&gt;

&lt;p&gt;In recent years, PHP has added strict typing features. This means function and method parameters can explicitly set a type for the incoming parameters and return types. A runtime exception will be thrown if the incoming value is not the expected type. If you see this directive:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;At the top of a file, then the types in that file will be treated as strict. This means that type strictness in files may differ. This enables large applications to migrate to strict types one file at a time.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// This is allowed in PHP: $id is a string now.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'1'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// This would trigger a TypeError.&lt;/span&gt;
&lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// This would be fine.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A &lt;code&gt;?&lt;/code&gt; in front of a type means that value is nullable (it can also be null).&lt;/p&gt;

&lt;p&gt;PHP's type system can be a source of confusion or errors. Code should be highly aware of what type a variable is at any given time and that it can change. Many people recommend the use of strict types where possible.&lt;/p&gt;

&lt;p&gt;More info about types in PHP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.php.net/manual/en/language.types.declarations.php" rel="noopener noreferrer"&gt;https://www.php.net/manual/en/language.types.declarations.php&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.brainbell.com/php/strict-type.html" rel="noopener noreferrer"&gt;https://www.brainbell.com/php/strict-type.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  PHP Arrays – Learn To Love Them
&lt;/h2&gt;

&lt;p&gt;One of the most common types of data structure in PHP is arrays. PHP developers use arrays for all kinds of things – often in place of data objects which might not be the best idea! Arrays in PHP are very flexible because they are actually hashmaps. This means the array key does not have to be sequential or even numeric. Filling an array with disconnected integer indexes does not mean that all the array cells between will be reserved:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$houses&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Blue'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$houses&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Red'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;array_key_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$houses&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 0 (false)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Array keys can be strings:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'username'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'tonystark'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'ironman123'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// This can also be defined like so:&lt;/span&gt;

&lt;span class="nv"&gt;$config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'username'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'tonystark'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'password'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'ironman123'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can also declare a value as an empty array ahead of time, or you can assign many values which will be given sequential, numeric keys starting at 0:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$superheros&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// empty array.&lt;/span&gt;

&lt;span class="nv"&gt;$superheros&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Superman'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Batman'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Black Widow'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Ironman'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;print_r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$superheros&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// [0] =&amp;gt; Superman, [1] =&amp;gt; Batman ...etc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;All of the keys in a PHP array don't even have to be the same type! PHP.net has a lot of documentation about arrays and PHP provides many built in functions for sorting and manipulating arrays.&lt;/p&gt;
&lt;h2&gt;
  
  
  PHP Syntax
&lt;/h2&gt;

&lt;p&gt;PHP's syntax is slightly related to C. Some highlights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All variables begin with a &lt;code&gt;$&lt;/code&gt;. Class names, method and function names do not.&lt;/li&gt;
&lt;li&gt;All statements end with a &lt;code&gt;;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Control structures are wrapped in curly braces &lt;code&gt;{}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;White space and indenting does not matter.&lt;/li&gt;
&lt;li&gt;PHP code begins with &lt;code&gt;&amp;lt;?php&lt;/code&gt; (sometimes just &lt;code&gt;&amp;lt;?&lt;/code&gt; for short) and ends with a &lt;code&gt;?&amp;gt;&lt;/code&gt;. This code &lt;em&gt;can&lt;/em&gt; be interspersed in regular HTML... but modern applications don't do that anymore. If a file ends with PHP code, the closing tag is left off.&lt;/li&gt;
&lt;li&gt;Strings can be wrapped in single or double quotes. Special characters (like &lt;code&gt;\n&lt;/code&gt; for a newline) will only be recognized in double quotes.&lt;/li&gt;
&lt;li&gt;Many projects have a coding standards guide or loose policy to keep things consistent. For example, class names begin with a capital.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article gives a quick overview of PHP syntax: &lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/ericchapman" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F462537%2F34d1837f-a6d2-47ef-84e7-3090e74c3f16.png" alt="ericchapman"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/ericchapman/my-beloved-php-cheat-sheet-7dl" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;My beloved PHP cheat sheet&lt;/h2&gt;
      &lt;h3&gt;Eric The Coder ・ Dec 17 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#php&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#laravel&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Code Analysis
&lt;/h2&gt;

&lt;p&gt;The PHP community has created many excellent tools which enable you to perform analysis on the style, quality, and even correctness of your PHP code. These static analysis tools can be valuable to help keep your projects on a set coding style, or to find code smells in your application. While there are &lt;a href="https://github.com/exakat/php-static-analysis-tools" rel="noopener noreferrer"&gt;many PHP analysis tools&lt;/a&gt; to choose from, some popular ones are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/PHPCSStandards/PHP_CodeSniffer/" rel="noopener noreferrer"&gt;PHP Code Sniffer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/PHP-CS-Fixer/PHP-CS-Fixer" rel="noopener noreferrer"&gt;PHP Code Style Fixer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/phpstan/phpstan" rel="noopener noreferrer"&gt;PHP Stan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://getpsalm.org/" rel="noopener noreferrer"&gt;Psalm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/etsy/phan" rel="noopener noreferrer"&gt;Phan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sebastianbergmann/phpcpd" rel="noopener noreferrer"&gt;PHP CPD (Copy-Paste Detector)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Autoloading and Composer
&lt;/h2&gt;

&lt;p&gt;If your PHP application entry point is the index.php file... no other files of source code will be run or referenced unless they are included into the requested file. So if you run a file “test.php”, only the code in that file will be available. Historically projects would use several include or require statements to bring other code in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="c1"&gt;// File index.php&lt;/span&gt;

&lt;span class="k"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'config.php'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Execution will stop if this file is not found.&lt;/span&gt;
&lt;span class="k"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'functions.php'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// If the file isn't found, execution continues anyway.&lt;/span&gt;
&lt;span class="k"&gt;require_once&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user.php'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Ensure this isn't included multiple times.&lt;/span&gt;

&lt;span class="nv"&gt;$foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'bar'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may see many includes like the above at the top of an index.php file which will bring in class definitions, functions, etc which are needed by the application.&lt;/p&gt;

&lt;p&gt;Modern PHP applications don't use includes like this anymore. &lt;a href="https://getcomposer.org/" rel="noopener noreferrer"&gt;Composer is the package manager for PHP&lt;/a&gt;. It also provides an autoloader which will include class (object definition) files automatically, only once they are needed by the application. This prevents including code that is never used. Composer when configured in a project creates a &lt;code&gt;vendor/&lt;/code&gt; directory where it will place the autoloader and any installed packages. If you see a vendor directory or a composer.json file at the root of a project, that's how you can tell that Composer is being used. Don't be surprised if many older applications don't use it. PEAR is an older system used to install packages into PHP projects.&lt;/p&gt;

&lt;p&gt;In the case of Composer autoloading being used, you will see this at the top of every file in an application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;require_once&lt;/span&gt; &lt;span class="s1"&gt;'vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Composer lets us pull in dependencies (like the open source projects found on &lt;a href="https://packagist.org/" rel="noopener noreferrer"&gt;Packagist&lt;/a&gt;) and they will be installed in the vendor directory and become instantly available to our projects. We can pin them to certain version numbers, update our dependencies and declare some packages to be for the dev environment only (like testing and static analysis tools).&lt;/p&gt;

&lt;p&gt;Understanding and learning Composer is very relevant for modern PHP development. An intro to Composer is found here: &lt;a href="https://getcomposer.org/doc/00-intro.md" rel="noopener noreferrer"&gt;https://getcomposer.org/doc/00-intro.md&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  PHP Resources &amp;amp; Looking Ahead
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;PHP is a very old language and the tutorials, StackOverflow answers, and blog posts about PHP that you might find online can be very outdated and include many security flaws.&lt;/em&gt;&lt;/strong&gt; I recommend not using resources or code from over 3 years ago.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.php.net/supported-versions.php" rel="noopener noreferrer"&gt;PHP's versions have a defined lifecycle&lt;/a&gt;. Make sure you are using a supported version.&lt;/p&gt;

&lt;p&gt;PHP has some of the best official documentation around, including examples and user-contributed comments. The official docs are found at &lt;a href="https://www.php.net/" rel="noopener noreferrer"&gt;https://www.php.net/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The official publication (magazine) for PHP is &lt;a href="https://www.phparch.com/" rel="noopener noreferrer"&gt;php[architect]&lt;/a&gt;. I've had a subscription for several years and sometimes write for the magazine. A lot of high-quality targeted information in here.&lt;/p&gt;

&lt;p&gt;One of the top resources for learning modern PHP is the website &lt;a href="https://phptherightway.com/" rel="noopener noreferrer"&gt;https://phptherightway.com/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The following is a large list of useful resources:&lt;br&gt;&lt;br&gt;
&lt;a href="https://odan.github.io/learn-php/" rel="noopener noreferrer"&gt;https://odan.github.io/learn-php/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The website &lt;a href="https://laracasts.com/" rel="noopener noreferrer"&gt;https://laracasts.com/&lt;/a&gt; is full of very high quality PHP and web development tutorials. Many are specific to the Laravel framework, but there are also many that cover PHP in general and modern best practises. I love this resource so much, that despite not using Laravel, I have a lifetime subscription to LaraCasts. Suggested series:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://laracasts.com/series/php-for-beginners" rel="noopener noreferrer"&gt;Intro to PHP – FREE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://laracasts.com/series/visual-studio-code-for-php-developers" rel="noopener noreferrer"&gt;Visual Studio Code for PHP Developers – FREE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://laracasts.com/series/object-oriented-principles-in-php" rel="noopener noreferrer"&gt;Object Oriented PHP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://laracasts.com/series/solid-principles-in-php" rel="noopener noreferrer"&gt;Solid Design Principles in PHP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://laracasts.com/series/design-patterns-in-php" rel="noopener noreferrer"&gt;Design Patterns in PHP&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is a similar screencasts website for the other top PHP framework, Symfony (the one I use) found at &lt;a href="https://symfonycasts.com/" rel="noopener noreferrer"&gt;https://symfonycasts.com/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The most popular editors for PHP are VSCode (what I use) &amp;amp; SublimeText. If you prefer a full IDE, the best is PHPStorm, but it is a commercial product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enjoy Your Journey
&lt;/h2&gt;

&lt;p&gt;Today, PHP is a modern, flexible, popular programming language. The community is very large and welcoming, and the wealth of resources about PHP is vast and varied. I enjoy using PHP and the language continues to receive core updates and new versions which just keep getting better. &lt;a href="https://www.php.net/releases/8.0/en.php" rel="noopener noreferrer"&gt;PHP 8 was released very recently&lt;/a&gt;. Welcome to PHP and thanks for reading!&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
&lt;a href="https://blog.syntaxseed.com/learn-php-for-experienced-developers/" rel="noopener noreferrer"&gt;Originally Published on Blog.SyntaxSeed.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>tutorial</category>
      <category>onboarding</category>
      <category>programming</category>
    </item>
    <item>
      <title>DarkLang Intro And First Impressions</title>
      <dc:creator>SyntaxSeed (Sherri W)</dc:creator>
      <pubDate>Fri, 08 Jan 2021 16:14:56 +0000</pubDate>
      <link>https://dev.to/syntaxseed/darklang-intro-and-first-impressions-46oi</link>
      <guid>https://dev.to/syntaxseed/darklang-intro-and-first-impressions-46oi</guid>
      <description>&lt;p&gt;A colleague mentioned a new language and serverless environment called Dark (or DarkLang if you don't want a zillion unrelated search results). It sounded interesting so I created an account to check it out.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is DarkLang?
&lt;/h2&gt;

&lt;p&gt;Dark is a language, environment, online editor and serverless deployment infrastructure to create and serve backends for your applications. It lends itself well to APIs, bots and even CRUD applications. There's nothing to set up on your machine, everything is done online in your Dark account. Everything you write in their online editor is instantly deployed and consumable.&lt;/p&gt;

&lt;h2&gt;
  
  
  How To Get Started
&lt;/h2&gt;

&lt;p&gt;Dark is currently in Beta but they are open for new signups. I created an account on their website &lt;a href="https://darklang.com/"&gt;https://darklang.com/&lt;/a&gt; and was instantly brought into the online editor to write my first endpoint with a 2 minute tutorial.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RQzTeEng--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/e788g98nfgvwada1mfp6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RQzTeEng--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/e788g98nfgvwada1mfp6.png" alt="The DarkLang Online Editor and Tutorial"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The guided tutorial helped me create a basic GET endpoint and return a Hello World result. When this was complete it provided a link to open a more complex CRUD example application.&lt;/p&gt;

&lt;p&gt;Ellen, one of the founders of Dark, has a great introduction YouTube video which I watched after creating this hello world example.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/orRn2kTtRXQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;From here, Dark has a much more in depth &lt;a href="https://docs.darklang.com/your-first/"&gt;Your First App tutorial&lt;/a&gt; which will be my next learning step.&lt;/p&gt;

&lt;h2&gt;
  
  
  First Impressions
&lt;/h2&gt;

&lt;p&gt;I'm very intrigued by the absolutely minimal barrier to entry here. No editor or software to install, no dev environment to set up, nothing to run or configure, no deployment. I created an API endpoint with utterly zero fuss. Awesome!&lt;/p&gt;

&lt;p&gt;As cool as that is, it brings to mind some questions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How do I prevent myself from developing directly in production with all the risks that entails?&lt;/li&gt;
&lt;li&gt;How do I control when a new update becomes live? I saw brief mentions of feature flags, but couldn't readily see how to use them.&lt;/li&gt;
&lt;li&gt;Will there be mechanisms for testing my applications?&lt;/li&gt;
&lt;li&gt;How do I have my own backups of my Dark programs? It seems like if Dark goes down or ratchets up prices, then I'm stuck.&lt;/li&gt;
&lt;li&gt;What even is or will be Dark's pricing model? I'd like to know what I'm getting into.&lt;/li&gt;
&lt;li&gt;How well will Dark scale?&lt;/li&gt;
&lt;li&gt;Version control or collaboration? This seems designed for only one developer to work on a project with no way to roll back changes.&lt;/li&gt;
&lt;li&gt;What if I don't want to use the Dark online editor?&lt;/li&gt;
&lt;li&gt;Committing to Dark seems to be the highest level of trust you'd ever have to place on a tool or service, since you don't have control of literally any part of your Dark applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Other Feedback
&lt;/h2&gt;

&lt;p&gt;At first blush the online editor is snappy, fast and pretty cool. However it lacks many convenience features like the ability to resize the blocks you create to change how long lines will wrap. There seems to be no way to enter blank lines to make your code readable. And comments are just a special kind of variable declaration which makes it so they don't stand out.&lt;/p&gt;

&lt;p&gt;Account management is still very Beta. You can't delete your unwanted canvases, rename them or duplicate them if you want to try something out. You can't configure your account profile or even change your name, email and password as far as I can see.&lt;/p&gt;

&lt;p&gt;If I was one of the founders of Dark, I would change all my marketing to name this DarkLang not Dark. Anyone googling for future development questions about Dark will never get specific search results because the word 'dark' is so generic and will also bring up articles that mention 'dark mode'. Naming this just 'dark' will make it much harder to promote and use.&lt;/p&gt;

&lt;p&gt;Dark has a &lt;a href="https://roadmap.darklang.com/"&gt;product roadmap&lt;/a&gt; that mentions some of these concerns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ideas For Uses
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create mock APIs for testing my applications written in other languages.&lt;/li&gt;
&lt;li&gt;Fast creation of SlackBots and similar.&lt;/li&gt;
&lt;li&gt;Glue to join two or more other APIs together.&lt;/li&gt;
&lt;li&gt;Provide a wrapper for isolating or extending 3rd party APIs.&lt;/li&gt;
&lt;li&gt;Rapid development of demos and proofs of concept.&lt;/li&gt;
&lt;li&gt;API solution for mobile app development.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;For me... I think I will file this under: &lt;em&gt;"Looks really cool and has potential, but needs to mature. Check it out again in a year"&lt;/em&gt;. :D&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
&lt;a href="https://blog.syntaxseed.com/darklang-intro-and-first-impressions/"&gt;Originally Published on Blog.SyntaxSeed.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>darklang</category>
      <category>serverless</category>
      <category>beginners</category>
      <category>review</category>
    </item>
    <item>
      <title>Let's Talk About: Coercive Software Design</title>
      <dc:creator>SyntaxSeed (Sherri W)</dc:creator>
      <pubDate>Thu, 29 Oct 2020 19:30:13 +0000</pubDate>
      <link>https://dev.to/syntaxseed/let-s-talk-about-coercive-software-design-2onk</link>
      <guid>https://dev.to/syntaxseed/let-s-talk-about-coercive-software-design-2onk</guid>
      <description>&lt;p&gt;We become developers with the understanding that our mission with the software we create is to meet the needs of users. But what happens when the software we create is being used to change or coerce the behaviour of users, rather than help them work, play and behave the way they want to? What are the ethical considerations of developing software that tries to manipulate users? Where does the profit-driven motivation go too far?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Coercive:&lt;/strong&gt; using force to persuade people to do things that they are unwilling to do. (Cambridge Dictionary)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I recently started thinking about this topic, when Facebook pushed out new changes that cut off my last method of checking my messages on my phone. I refuse to install the Messenger app, and instead I primarily use Facebook in the Chrome/Brave mobile browser on my phone. Facebook began as a website. I have always used it this way.&lt;/p&gt;

&lt;p&gt;A couple years ago they released an update that would tell me to download the Messenger app to view my messages. Since then I could turn on 'Desktop Mode' in my browser and still access my messages. In a broken layout with a horizontal scrollbar, but it was at least usable. Today, even Desktop Mode doesn't work. I get this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UrA17VQu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ejwncu2rnik01585iogv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UrA17VQu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ejwncu2rnik01585iogv.jpg" alt="Facebook Warning: Get Messenger to view your messages."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In theory I could find a mobile browser that lets me spoof the useragent and try that... but using a different browser would disrupt all my other activities on my phone, and I can't even be sure that would work - they were closing that loophole a few years ago. I've decided to stop trying to force Facebook to let me use it, and just stop using Facebook so much.&lt;/p&gt;

&lt;p&gt;Let's talk about this for a moment.&lt;/p&gt;

&lt;p&gt;Facebook spent considerable time drawing all of us in. Making themselves the de facto method of connecting with our friends and family. Few people in my circles call, text or email each other anymore. They use FB messages. Facebook became a necessary default in our lives, and they are now coercing me into their app riddled with privacy issues, onto my older phone with limited space for more apps.&lt;/p&gt;

&lt;p&gt;Facebook isn't even trying to meet my needs as a user. If I need to check the messages for my business page, I can still do so on my phone. So the code for the mobile messenger website is there.&lt;/p&gt;

&lt;p&gt;This type of coercive behaviour is everywhere now.&lt;/p&gt;

&lt;p&gt;If I visit many websites from my phone - Twitter, Reddit, Facebook, etc I get a popup that offers their mobile app. I can usually choose "Get The App" or "Not Now". There is never, ever, a "Don't ask me again" option. I'm nagged by these popups everywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Notification Hell
&lt;/h2&gt;

&lt;p&gt;One of many reasons I refuse to install social apps, is the bombardment of notifications and 'unread' indicators that are all over my digital experience these days. Those tiny read circles with numbers indicating messages I've yet to check. I disable these whenever I can, but they are still everywhere. Designed intentionally to press your buttons to make you clear them. I don't have my email push to my phone for this reason.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GgRq3FwS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nvjotlh51po2sgrnocle.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GgRq3FwS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nvjotlh51po2sgrnocle.jpg" alt="Strip of red notification icons"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I want to control when I'm notified about unread emails. I want to decide when I'm willing to work or be reachable, and when I'm not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coercion Examples
&lt;/h2&gt;

&lt;p&gt;I've seen other examples of software and websites trying to force my use of them in one way or another, often in ways that are detrimental to my user experience. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Opting me into the most invasive privacy or marketing settings by default.&lt;/li&gt;
&lt;li&gt;Burying important options down several layers deep in the settings.&lt;/li&gt;
&lt;li&gt;Intentionally hiding phone numbers or email addresses from a company's support page, even though these exist.&lt;/li&gt;
&lt;li&gt;Delivering notifications in a staggered asynchronous way so that even once you've 'cleared' all your notifications, more appear even if they are from hours before you last cleared them all.&lt;/li&gt;
&lt;li&gt;Intentionally making features unavailable on the web version and limiting it to app users.&lt;/li&gt;
&lt;li&gt;Unethical billing practises such as opting users into auto-renew subscriptions without their consent. Ignoring cancellation requests.&lt;/li&gt;
&lt;li&gt;Disguising buttons to encourage accident clicks. The Amazon Prime signup button is a good example of this.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This is a topic I've just begun to think about, so I don't have a lot to say about what we as developers should be doing about this topic. Do we just take the approach that "well Facebook is free so you can't complain"? Does that even apply if I don't even have the choice to pay and use it how I want?&lt;/p&gt;

&lt;p&gt;Do we as developers have the power, or the desire to push back against these practises?&lt;/p&gt;

&lt;p&gt;I know that I have decided to step back from my use of Facebook over this issue, but it is a steep price to pay, since I'll lose out on a lot of connections. And even if I choose to take this stance, none of my friends or family care enough about privacy to make the same decision.&lt;/p&gt;

&lt;p&gt;What do you think about it fellow developers? And what other examples of this behaviour have you seen?&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
&lt;a href="https://blog.syntaxseed.com/lets-talk-about-coercive-software-design/"&gt;Originally Published on Blog.SyntaxSeed.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ux</category>
      <category>design</category>
      <category>users</category>
      <category>ethics</category>
    </item>
    <item>
      <title>Combating Phone Addiction: Try, Fail &amp; Try Again</title>
      <dc:creator>SyntaxSeed (Sherri W)</dc:creator>
      <pubDate>Thu, 19 Dec 2019 15:43:56 +0000</pubDate>
      <link>https://dev.to/syntaxseed/combating-phone-addiction-try-fail-try-again-4k17</link>
      <guid>https://dev.to/syntaxseed/combating-phone-addiction-try-fail-try-again-4k17</guid>
      <description>&lt;p&gt;&lt;em&gt;Let me preface this by saying that this post discusses my own experiences and observations in my life. Your perspective may vary, and what works for me or is a problem for me, may not be so in your life. That's ok, we're all different and awesome.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;My husband and I are on round 4 (ish) of our attempts to renew our resolutions to find a healthier balance of our phone and online use. As a web developer it's tempting to almost live online, but at least for us, that's a fast track to unhappiness. Luckily it hasn't been an extreme problem- it hasn't interfered with our careers or parenting or physical health. But there have definitely been some concequences of too much phone  use.&lt;/p&gt;

&lt;p&gt;For me it's social media, tutorials and articles, and an endless stream of screencasts and videos of conference talks. It used to be mobile browser games too. It's fluffy amateur fiction and lots of Twitter. For my husband it was games, then YouTube videos, news (often not even about our own country), Reddit and comedy specials. Our phones are endless sources of dopamine shots and minimally interesting or entertaining material.&lt;/p&gt;

&lt;p&gt;This temptation catches us on our phones during the commercials when watching a broadcast TV show. In the washroom, or on the couch while the children play around us like that heartbreaking &lt;a href="https://www.youtube.com/watch?v=oiKj0Z_Xnjc"&gt;Papaoutai video {French}&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To clarify - my kids do not want for loving, affectionate and involved parenting. I'm a work-from-home parent until September and my kids are snuggled and given heaps of attention. What's missing is getting down on the floor and &lt;em&gt;playing&lt;/em&gt; games like pretend and checkers and the like, more often than we do now.&lt;/p&gt;

&lt;p&gt;Some of the things I &lt;em&gt;know&lt;/em&gt; have been a consequence of too much phone use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I read WAY fewer books than I used to.&lt;/li&gt;
&lt;li&gt;I have less time for non-online hobbies.&lt;/li&gt;
&lt;li&gt;Less time for meaningful board and video gaming.&lt;/li&gt;
&lt;li&gt;We go outside less, to just play in the neighbourhood or yard.&lt;/li&gt;
&lt;li&gt;Less frequent playing with my kids.&lt;/li&gt;
&lt;li&gt;Less meaningful learning cemented with putting what I learn into use.&lt;/li&gt;
&lt;li&gt;Almost zero time spent bored or daydreaming.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You know what? Each of the things I'd rather be doing require a tiny modicum of energy more than just reaching for our phones. They require a longer attention span too. Our attention spans are another muscle we've noticed has atrophied like our tolerance for boredom, or our capacity for unguided imaginative thought. And we humans are masters of finding the path of least resistance.&lt;/p&gt;

&lt;p&gt;So, we fight this battle. Set limits. Fall off the wagon. And get back on.&lt;/p&gt;

&lt;p&gt;Our latest round of limits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No phones in the washroom. It's like a force field keeping them out of there. Bring a book.&lt;/li&gt;
&lt;li&gt;A limited block of free browsing each day.&lt;/li&gt;
&lt;li&gt;If we &lt;em&gt;need&lt;/em&gt; to use our phone - for work, or looking things up, it happens in the kitchen - the least comfortable room.&lt;/li&gt;
&lt;li&gt;No phones on the couches or when watching a show together.&lt;/li&gt;
&lt;li&gt;If I want to read a bunch of articles, or a screencast, it happens at my computer when I'm in 'work mode' and can practise along or make notes.&lt;/li&gt;
&lt;li&gt;We continue to make use of a DNS filtering service to block distracting sites at certain times of day.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also re-established a weekly schedule, blocking our evenings into a balance of time for work, relaxation, and side-projects. This helps us to feel like we are never lacking in time for the things we want and need to do. Time for each other, time to be productive, and time for relaxing fun. Thursdays are also family board game night. Wednesdays are date night - even if that's just watching a show then playing some co-op video games. This is a system we have used in the past to much benefit, we just fell out of the routine lately. We try to plan fun/R&amp;amp;R (Rest &amp;amp; Relaxation) nights on our most exhausting days when work or kids' after school activities make the days feel long.&lt;/p&gt;

&lt;p&gt;We have 3 R&amp;amp;R nights each week. 3 nights for work or side-projects. And one 'flex' night to use as needed or plan social outings. This type of scheduling isn't for everyone. But it helps us feel like we have a balance. No guilt on fun nights that we should be working. And less resistance to work nights because we know we have plenty of relax time.&lt;/p&gt;

&lt;p&gt;An additional resolution - also exacerbated by too much phone use, is our tendency to go to bed too late. When you have kids, that precious kid-free time in the evening is gold. But staying up too late is robbing from ourselves tomorrow. So an addition to our phone limits and schedule are strict bedtimes that will help us feel fresher and less frazzled the next day.&lt;/p&gt;

&lt;p&gt;As I write this, it's now 3 days into our renewed efforts. It's not easy. The temptation and FOMO (Fear Of Missing Out) is real. In our conversations with friends and colleagues we know that we aren't alone in these struggles. I hope that this post can be a way to reach out to others and share our story. Find out what works for others. And hold ourselves accountable.&lt;/p&gt;

&lt;p&gt;What's been your experience in this area? Any tips that work for you? Do you have other resolutions that are top of mind as we head into the new year? You can do it! &lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
&lt;a href="https://blog.syntaxseed.com/combating-phone-addiction-try-fail-try-again/"&gt;Originally Published on Blog.SyntaxSeed.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Photo by Marjan Grabowski&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>watercooler</category>
      <category>healthydebate</category>
    </item>
    <item>
      <title>Legacy PHP Application: PHP Code Sniffer Compatibility Standard</title>
      <dc:creator>SyntaxSeed (Sherri W)</dc:creator>
      <pubDate>Wed, 20 Nov 2019 17:03:55 +0000</pubDate>
      <link>https://dev.to/syntaxseed/legacy-php-application-php-code-sniffer-compatibility-standard-51m6</link>
      <guid>https://dev.to/syntaxseed/legacy-php-application-php-code-sniffer-compatibility-standard-51m6</guid>
      <description>&lt;p&gt;Part 1 of this series covers a tour of my 14+ year old legacy CMS called LampLight and it continues with my use of command line code analysis tools to migrate it from PHP v 5.6 to 7.3. In this part I'll use &lt;a href="https://github.com/squizlabs/PHP_CodeSniffer" rel="noopener noreferrer"&gt;PHP_CodeSniffer&lt;/a&gt; to check my applications compatibility with PHP v 7.3 and beyond.&lt;/p&gt;

&lt;p&gt;Let's not fuss around, and instead dive right into the meat of this post. At the root of my project I run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;phpcs --standard=PHPCompatibility --extensions=php,inc,lib -s --runtime-set testVersion 7.3- . 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hot damn it's not too bad! A couple pages of errors flagged, mostly boiling down to these two:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fl4ynjb1aosvd4wdgivdy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fl4ynjb1aosvd4wdgivdy.png" alt="PHP Compatibility Output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Line Ending Madness
&lt;/h2&gt;

&lt;p&gt;Good grief, I can't seem to escape this mixed line endings issue. It's been flagged and fixed repeatedly. Opening the file in VSCode, reveals down in the bottom right corner an indicator of &lt;code&gt;CRLF&lt;/code&gt; meaning Windows style endings. I want everything to use Linux style endings (LF), I work on a Linux machine, this shouldn't be complicated. Unfortunately a lot of my old code was written on Windows.&lt;/p&gt;

&lt;p&gt;The odd thing is that PHP_CodeSniffer didn't even flag all the files that were problematic. I suppose it's only noticing files where there are both types of endings.&lt;/p&gt;

&lt;p&gt;At this point I ran through several attempts to fix it using tools like dos2unix and other scripts off of StackOverflow, my usual git reset tricks, and more. It was an hour-long tangent and nothing seemed to work.&lt;/p&gt;

&lt;p&gt;I discovered that most of these tools, including Git's methods, can convert files with consistent line endings... but once a file has MIXED endings, they aren't automatically converted. Though I can't figure out why my fixers weren't doing it. UG.&lt;/p&gt;

&lt;p&gt;Ultimately I ended up opening every single file in VSCode and manually select-all and convert to LF endings. It took me about 10 minutes which is way less time than I spent researching it. I'm now fairly certain that all text files use LF line endings. (Knock on wood.)&lt;/p&gt;

&lt;p&gt;Running the PHP_CodeSniffer command again and... AAARRRGGGH! It's flagging one file as still having mixed line endings. Opening it in VSCode indicates LF endings. Using my bash &lt;code&gt;cat&lt;/code&gt; command replacement &lt;a href="https://github.com/sharkdp/bat" rel="noopener noreferrer"&gt;bat&lt;/a&gt; on the file, shows mixed endings indeed.&lt;/p&gt;

&lt;p&gt;So in VSCode I select all and convert to CRLF and then back again to LF endings. Drum roll... hallelujah PHP_CodeSniffer no longer reporting mixed line ending issues. VSCode is lacking in this area. It needs a 'mixed' indicator.&lt;/p&gt;

&lt;p&gt;Let's move on to the real issues that PHP_CodeSniffer revealed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Farewell get_magic_quotes_gpc()
&lt;/h2&gt;

&lt;p&gt;Well, well, I'll try not to blush as I write this, but PHP_CodeSniffer is flagging a few uses of &lt;code&gt;get_magic_quotes_gpc()&lt;/code&gt; in my code. A dig into the PHP docs reveals that this oft-maligned feature of PHP was &lt;em&gt;removed&lt;/em&gt; as of PHP 5.4.0! So, this is clearly a hold-over of some very, very, very old code. Let's look at what it's doing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;stripSlashesDeep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;is_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;array_map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'stripSlashesDeep'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;stripslashes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;get_magic_quotes_gpc&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$_GET&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;stripSlashesDeep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_GET&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$_POST&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;stripSlashesDeep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_POST&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$_COOKIE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;stripSlashesDeep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_COOKIE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This first instance is in my bootstrap file and is just cleaning the automatically inserted slashes from the request globals. I'll just remove this completely.&lt;/p&gt;

&lt;p&gt;The final instance of magic quotes is in a string escaping method in my database class/facade which wraps the mysqli functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;escapeStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$inStr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$stripSlashes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// If not already connected.&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stripSlashes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;            
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;get_magic_quotes_gpc&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nv"&gt;$inStr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;stripslashes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$inStr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nv"&gt;$inStr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mysqli_real_escape_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;dbc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$inStr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$inStr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since it's no longer needed I'll just remove the section resulting in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;escapeStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$inStr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$stripSlashes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// If not already connected.&lt;/span&gt;
        &lt;span class="nv"&gt;$inStr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mysqli_real_escape_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;dbc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$inStr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$inStr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now is a good time for a test of the application and a &lt;code&gt;git commit&lt;/code&gt;. What's next?&lt;/p&gt;

&lt;h2&gt;
  
  
  Indirect Access Ambiguity
&lt;/h2&gt;

&lt;p&gt;The final error says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Indirect access to variables, properties and methods will be evaluated strictly in left-to-right order since PHP 7.0. Use curly braces to remove ambiguity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This error is flagged in two spots. Let's look at the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"SERVER_NAME"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$oldservername&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well, well how embarrassing. This is actually a typo and the two dollar signs shouldn't be there. Easy enough to fix. The other instance is the same.&lt;/p&gt;

&lt;p&gt;Had this been a real use of variable variable names, or indirect access to variables... we can use curly braces to specify how to evaluate it. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$$whichVar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"New value"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;${$whichVar}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"New value"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this issue fixed, let's commit to Git, then run the command one more time to verify that this PHP_CodeSniffer isn't finding anything else with this compatibility check. Great!&lt;/p&gt;

&lt;h2&gt;
  
  
  Migration Wrap Up
&lt;/h2&gt;

&lt;p&gt;One of the most difficult parts of this migration process is that none of my older projects have automated tests of any kind. This exercise has really driven home why I need them and cemented my existing determination to create tests with all future projects. That said however, it has been surprisingly easy to migrate each individual project, with the help of these excellent tools. The main challenge is the sheer number of projects I have to migrate, and my limited time to allocate to this process.&lt;/p&gt;

&lt;p&gt;In summary, here are the CLI tools I've been using:&lt;/p&gt;

&lt;p&gt;Can be safely run automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php-cs-fixer fix . --rules=full_opening_tag,no_closing_tag,@PSR1,@PSR2 --verbose --dry-run --using-cache=no
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php-cs-fixer fix . --rules=@PHP70Migration,@PHP71Migration,@PHP73Migration --verbose --dry-run --using-cache=no
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Should probably do manually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php-cs-fixer fix . --rules=@PHP70Migration:risky,@PHP71Migration:risky,-declare_strict_types,-void_return --verbose --dry-run --using-cache=no --allow-risky=yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;phpcs --standard=PHPCompatibility --extensions=php,inc,lib --runtime-set testVersion 7.3- . 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Plus:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clean out commented out or dead code.&lt;/li&gt;
&lt;li&gt;Remove abandoned tiny projects and proof of concepts that are lying around inside other projects.&lt;/li&gt;
&lt;li&gt;Organize project structure.&lt;/li&gt;
&lt;li&gt;Get it running on my local dev environment.&lt;/li&gt;
&lt;li&gt;Fix obvious issues like the use of __autoload() and count().&lt;/li&gt;
&lt;li&gt;Migrate Mercurial to Git.&lt;/li&gt;
&lt;li&gt;Full manual test on PHP v 7.3.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It would be a great idea to integrate these types of checks into your Continuous Integration process, or at least in a pre-push or pre-commit Git hook to help keep these issues from sneaking back in. Especially style issues that aren't caught by tests. This is something I'm in the process of doing myself.&lt;/p&gt;

&lt;p&gt;I hope this series was helpful, and has given you a starting point for migrating legacy PHP projects, using command line analysis tools, and trusting automated fixer to tidy and correct your code.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
&lt;a href="https://blog.syntaxseed.com/legacy-php-application-php-code-sniffer-compatibility-standard/" rel="noopener noreferrer"&gt;Originally Published on Blog.SyntaxSeed.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>legacycode</category>
      <category>codeanalysis</category>
      <category>maintenance</category>
    </item>
    <item>
      <title>Legacy PHP Application: PHP CS Fixer &amp; PHP Code Sniffer for PSR1 &amp; PSR2</title>
      <dc:creator>SyntaxSeed (Sherri W)</dc:creator>
      <pubDate>Tue, 05 Nov 2019 00:02:00 +0000</pubDate>
      <link>https://dev.to/syntaxseed/legacy-php-application-php-cs-fixer-php-code-sniffer-for-psr1-psr2-15be</link>
      <guid>https://dev.to/syntaxseed/legacy-php-application-php-cs-fixer-php-code-sniffer-for-psr1-psr2-15be</guid>
      <description>&lt;p&gt;Part 1 of this series covers a tour of my 14+ year old legacy CMS called LampLight and it continues with my use of command line code analysis tools to migrate it from PHP v 5.6 to 7.3. In this part we'll continue to use PHP CS Fixer to clean up the code, and will then move on to use PHP Code Sniffer for even more tidying.&lt;/p&gt;

&lt;p&gt;My last few uses of &lt;a href="https://github.com/FriendsOfPHP/PHP-CS-Fixer"&gt;PHP Coding Standards Fixer&lt;/a&gt;, are to check for &lt;a href="https://www.php-fig.org/psr/psr-1/"&gt;PSR1&lt;/a&gt; and &lt;a href="https://www.php-fig.org/psr/psr-2/"&gt;PSR2&lt;/a&gt; compliance. These PSRs cover a baseline of code style conventions common among PHP projects.&lt;/p&gt;

&lt;p&gt;Note that PHP CS Fixer provides rulesets for these PSRs, but they do not cover ALL of the rules found in the PSRs. For now I'll just start with these, since it's an easy process and a discontinued project.&lt;/p&gt;

&lt;p&gt;First, running the ruleset for PSR1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php-cs-fixer fix . --rules=@PSR1 --verbose --using-cache=no --dry-run
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Actually reveals no issues! This is because I fixed the line ending problem when I migrated this project from &lt;a href="https://dev.to/syntaxseed/migrating-mercurial-repos-to-git-23ee"&gt;Mercurial to Git&lt;/a&gt;. And the opening tags issue was solved in &lt;a href="https://dev.to/syntaxseed/legacy-php-application-code-analysis-with-php-cs-fixer-48ff"&gt;part 1 of this series&lt;/a&gt;. Well that was easy. So on to PSR2:&lt;/p&gt;

&lt;h2&gt;
  
  
  PHP CS Fixer and PSR2
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php-cs-fixer fix . --rules=@PSR2 --verbose --using-cache=no --dry-run
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This run however, reveals a TON of problems, in almost every file! Eeek!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dc0YAaSh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/tk521asilkr4umqxsd03.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dc0YAaSh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/tk521asilkr4umqxsd03.png" alt="PHP CS Fixer - @PSR2 Ruleset"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's no way I want to either automatically fix this many issues at once, or try to pick my way through each one. So, I'll use this output to pick out one rule at a time and run only that. Look it up to see what's involved and if it looks straightforward I'll let the fixer do it's thing and then test. When I'm happy I'll &lt;code&gt;git commit&lt;/code&gt; to checkpoint my changes. This way I'll work my way through all the rules covered by the &lt;code&gt;@PSR2&lt;/code&gt; ruleset.&lt;/p&gt;

&lt;p&gt;You'll notice that many of these rules deal with how whitespace is handled. This means there is very little risk in letting the fixer correct these automatically.&lt;/p&gt;

&lt;p&gt;This process worked well and problem-free for each of these rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no_trailing_whitespace&lt;/li&gt;
&lt;li&gt;no_trailing_whitespace_in_comment&lt;/li&gt;
&lt;li&gt;single_blank_line_at_eof&lt;/li&gt;
&lt;li&gt;indentation_type&lt;/li&gt;
&lt;li&gt;method_argument_space&lt;/li&gt;
&lt;li&gt;braces&lt;/li&gt;
&lt;li&gt;function_declaration&lt;/li&gt;
&lt;li&gt;no_spaces_inside_parenthesis&lt;/li&gt;
&lt;li&gt;no_spaces_after_function_name&lt;/li&gt;
&lt;li&gt;line_ending&lt;/li&gt;
&lt;li&gt;lowercase_keywords&lt;/li&gt;
&lt;li&gt;lowercase_constants&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And these were all of the PSR2 rules that were flagged for my project. Turns out that I had no issues with any of these, and could have run the entire ruleset automatically.&lt;/p&gt;

&lt;p&gt;One odd thing that kept creeping up is that the line endings kept having to be re-fixed on several files. Not sure what went on there. But it seems to have finally stayed fixed.&lt;/p&gt;

&lt;p&gt;For the purposes of this project, this is it for what I wanted to do with PHP CS Fixer. Let's move on to another awesome tool for PHP code analysis.&lt;/p&gt;

&lt;h2&gt;
  
  
  PHP Code Sniffer
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/squizlabs/PHP_CodeSniffer"&gt;PHP Code Sniffer&lt;/a&gt; aka PHP_CodeSniffer is another command line tool you can use to analyze your code based on various standards. On my legacy applications like this one, it flags a &lt;strong&gt;TON&lt;/strong&gt; of issues. For this case, I'm only interested in checking for problems with the current version of PHP or future deprecations.&lt;/p&gt;

&lt;p&gt;This is where the &lt;code&gt;PHPCompatibility&lt;/code&gt; standard for PHP_CodeSniffer comes into play. But first, just for fun, let's see if PHP_CodeSniffer picks up any PSR2 violations that PHP CS Fixer missed. Use the &lt;code&gt;-s&lt;/code&gt; flag to make sure that each error also indicates which sniff was violated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;phpcs --standard=PSR2 -s .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Woah! This tool finds many things not covered by PHP CS Fixer! From the output we can see that all items marked with an [x] can be fixed automatically if we change to the bundled tool &lt;code&gt;phpcbf&lt;/code&gt;. In my terminal PHP_CodeSniffer has reported pages upon pages of violations. Here are just a few:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rkccT_7k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/y551jmso3ux4n0iziavm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rkccT_7k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/y551jmso3ux4n0iziavm.png" alt="PHP Code Sniffer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can break down which 'sniffs' are in a given standard with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;phpcs --standard=PSR2 -e
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Using this list, I can run PHP_CodeSniffer on a single rule or 'sniff'. And begin to break down that giant list of violations into only the ones I want to fix. Here's the spaces instead of tabs one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;phpcs --sniffs=Generic.WhiteSpace.DisallowTabIndent -s .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The included tool &lt;a href="https://github.com/squizlabs/PHP_CodeSniffer/wiki/Fixing-Errors-Automatically"&gt;PHP Code Beautifier and Fixer&lt;/a&gt; aka Phpcbf can be used to fix these automatically. In most cases just replace the command name and it will work. First I'll &lt;code&gt;git commit&lt;/code&gt; my work up to now and give it a try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;phpcbf --sniffs=Generic.WhiteSpace.DisallowTabIndent .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Wow, this fixed 77 files for me! I'll do the same routine with only the few things I want PHP_CodeSniffer to deal with. I could spend way more time on this given how many errors PHP_CodeSniffer found, but again this is a discontinued project and I don't want to spend too much time. So I limit my fixes to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;phpcbf --sniffs=Generic.WhiteSpace.DisallowTabIndent .

phpcbf --sniffs=Generic.Functions.FunctionCallArgumentSpacing .

phpcbf --standard=Squiz --sniffs=Squiz.Functions.FunctionDeclarationArgumentSpacing .

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A few gotchas popped up during this process. To fix a specific sniff you must also specify the standard that sniff is found in. Also, in your output with the &lt;code&gt;-s&lt;/code&gt; flag, you'll see it says something like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Squiz.Functions.FunctionDeclarationArgumentSpacing.SpaceBeforeEquals&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;But the last part of this is a rule inside of the sniff. So I had to remove the &lt;code&gt;.SpaceBeforeEquals&lt;/code&gt; part to make sure it matches the actual containing sniff.&lt;/p&gt;

&lt;p&gt;This process required frequent reference to the output of &lt;code&gt;phpcs --standard=PSR2 -e&lt;/code&gt;, which I eventually just ran in another terminal panel.&lt;/p&gt;

&lt;p&gt;After a few of these individual sniffs were fixed I was losing track of where I was in relation to what PHP_CodeSniffer originally found. I wanted a more high-level view of what PHP_CodeSniffer is finding. To do so, I can specify a different report type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;phpcs --standard=PSR2 --report=source -s .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m-JOBPfN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3egovxzm9tx7hx4yzt70.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m-JOBPfN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3egovxzm9tx7hx4yzt70.png" alt="PHP CS Source Report"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oy.  I have to admit that at this stage of the process, the thought of tracking down each of these sniffs and fixing each one and testing it... just didn't seem worth it to me for rules that are largely stylistic in nature and for a discontinued project. So this is where I stopped with the PSR2 checks with PHP_CodeSniffer. I think this gives you, dear reader, enough of a handle on how to use this tool for these types of fixes.&lt;/p&gt;

&lt;p&gt;I get the impression that PHP_CodeSniffer is more powerful than PHP CS Fixer for these style-based PSR checks.&lt;/p&gt;

&lt;p&gt;What I really want to do, is address issues that actually affect my application running on PHP version 7.3 (and future versions). So in the next part of this series, I'll move on to using PHP_CodeSniffer to run sniffs in the PHPCompatibility standard, which will find real issues that need to be addressed.&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
&lt;a href="https://blog.syntaxseed.com/legacy-php-application-php-cs-fixer-php-code-sniffer-for-psr1-psr2/"&gt;Originally Published on Blog.SyntaxSeed.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>codeanalysis</category>
      <category>legacycode</category>
      <category>psr</category>
    </item>
    <item>
      <title>Legacy PHP Application: Code Analysis With PHP CS Fixer</title>
      <dc:creator>SyntaxSeed (Sherri W)</dc:creator>
      <pubDate>Fri, 25 Oct 2019 15:57:23 +0000</pubDate>
      <link>https://dev.to/syntaxseed/legacy-php-application-code-analysis-with-php-cs-fixer-48ff</link>
      <guid>https://dev.to/syntaxseed/legacy-php-application-code-analysis-with-php-cs-fixer-48ff</guid>
      <description>&lt;p&gt;In part one of this series we took a tour into my 14+ year old legacy CMS called LampLight. It's an oldie but a goodie and it needs some love because it's still in use by a couple clients and myself. We are migrating it from PHP v 5.6 to 7.3. In this part we'll use PHP CS Fixer to identify problems and clean things up.&lt;/p&gt;

&lt;h2&gt;
  
  
  PHP Short Tags and Closing Tags
&lt;/h2&gt;

&lt;p&gt;Talk has been cheap for some time regarding the deprecation of the short opening tag &lt;code&gt;&amp;lt;?&lt;/code&gt; for PHP, and its removal has had a few false starts. Finally, a &lt;a href="https://wiki.php.net/rfc/deprecate_php_short_tags" rel="noopener noreferrer"&gt;PSR for this change&lt;/a&gt; has passed and it will officially be deprecated in v 7.4. &lt;/p&gt;

&lt;p&gt;We also want to eliminate the closing PHP tag in files that contain only PHP. These two issues are quite straightforward, so let's use these as an easy dip-of-the-toe into using command line code analysis tools to have a look at our code. We can even use these tools to make the changes for us.&lt;/p&gt;

&lt;p&gt;I first commit all my work to my Git repo and push it to the remote.&lt;/p&gt;

&lt;p&gt;We'll use &lt;a href="https://github.com/FriendsOfPHP/PHP-CS-Fixer" rel="noopener noreferrer"&gt;PHP Coding Standards Fixer&lt;/a&gt; aka php-cs-fixer for this. It's a powerful tool to analyze code issues and fix them for you. At the root of my CMS project I run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php-cs-fixer fix &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--rules&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;full_opening_tag,no_closing_tag &lt;span class="nt"&gt;--verbose&lt;/span&gt; &lt;span class="nt"&gt;--dry-run&lt;/span&gt; &lt;span class="nt"&gt;--using-cache&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;no
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I rarely use the cache because I don't want it creating files in my project, and I use the &lt;code&gt;--dry-run&lt;/code&gt; flag to see what the output would be before actually doing anything. You can also use the &lt;code&gt;--diff&lt;/code&gt; flag to see what would be changed by the fixer in a diff format. You can see the only rules I'm running are for short tags and closing tag removal. This gives me a list of all the files which have a problem, and at the top a nice visual summary which looks like this for only one rule:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F7m3lx9miolw19fi0ssq5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F7m3lx9miolw19fi0ssq5.png" alt="PHP CS Fixer output summary"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All the green 'F's represent files that will be fixed. The dots are files with no fixes. That's a lot! I'm confident this is an easy fix that I trust to be done automatically so I remove the &lt;code&gt;--dry-run&lt;/code&gt; flag and run the command again. &lt;/p&gt;

&lt;p&gt;Now it's fixed my files for me. So easy! I do a full test of my application then commit the changes to Git. Not bad for 5 minutes on a Wednesday. And we are now familiar with PHP CS Fixer. A handy tool for every PHP developer's belt.&lt;/p&gt;

&lt;h2&gt;
  
  
  PHP Version Compatibility
&lt;/h2&gt;

&lt;p&gt;PHP CS Fixer has a lot of fixes available. Let's look them up. Visit the &lt;a href="https://mlocati.github.io/php-cs-fixer-configurator/" rel="noopener noreferrer"&gt;PHP CS Fixer Configurator Rules&lt;/a&gt; site to look up the available rules and rulesets. You may have to update the fixer and/or install additional rules.&lt;/p&gt;

&lt;p&gt;Ah ha! There are rules for checking PHP version compatibility. I'm most interested in the migration rule SETS (preceded by an @ symbol):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;@PHP70Migration and @PHP70Migration:risky&lt;/li&gt;
&lt;li&gt;@PHP71Migration and @PHP71Migration:risky&lt;/li&gt;
&lt;li&gt;@PHP73Migration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For some reason there doesn't seem to be a ruleset for 7.2. Oh well, let's use what we have.&lt;/p&gt;

&lt;p&gt;One by one we will run the fixer with a rule set. First with the &lt;code&gt;--dry-run&lt;/code&gt; flag. You could technically do all the rulesets at once by comma separating them... but I don't like to have to wade through a zillion problems at once.&lt;/p&gt;

&lt;p&gt;The sets labelled 'risky' should sometimes be fixed by hand instead of trusting the fixer to do them. You can look at the reasons why it's risky in the rule info in the Configurator and decide for yourself. Let's do the first non-risky one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php-cs-fixer fix &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--rules&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;@PHP70Migration &lt;span class="nt"&gt;--verbose&lt;/span&gt; &lt;span class="nt"&gt;--dry-run&lt;/span&gt; &lt;span class="nt"&gt;--using-cache&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;no
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Miraculously no problems reported! The risky rule next (note the additional &lt;code&gt;--allow-risky=yes&lt;/code&gt; flag), and I make sure it's only a dry-run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php-cs-fixer fix &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--rules&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;@PHP70Migration:risky &lt;span class="nt"&gt;--verbose&lt;/span&gt; &lt;span class="nt"&gt;--dry-run&lt;/span&gt; &lt;span class="nt"&gt;--using-cache&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;no &lt;span class="nt"&gt;--allow-risky&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Woah! A ton of issues, mostly for the declare_strict_types rule. Let's look that rule up in the Configurator site. Yup just like it sounds, it tries to force a strict types declaration at the top of the file. I don't want to do that, so can I add a rule exception to my ruleset? YES! Just add it to the rules list starting with a minus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php-cs-fixer fix &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--rules&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;@PHP70Migration:risky,-declare_strict_types &lt;span class="nt"&gt;--verbose&lt;/span&gt; &lt;span class="nt"&gt;--dry-run&lt;/span&gt; &lt;span class="nt"&gt;--using-cache&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;no &lt;span class="nt"&gt;--allow-risky&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fe9a7yyouo8l6oyulaazi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fe9a7yyouo8l6oyulaazi.png" alt="PHP CS Fixer - random api"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Much better, only a few issues, exclusively from the random_api_migration rule. We need to use the proper random functions. I'll go into each file and fix them up manually. Test and then &lt;code&gt;git commit&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  A 'Random' Gotcha
&lt;/h3&gt;

&lt;p&gt;When I first tried to manually fix the random_api_migration rule, I changed all instances of &lt;code&gt;rand()&lt;/code&gt; to &lt;code&gt;mt_rand()&lt;/code&gt;. PHP CS Fixer kept flagging the same errors, even though I was doing the change via the examples in the Configurator docs. I spent too much time thinking the fixer was still using a cache. Gave up and ran the fixer without the dry-run flag. Lo and behold it changed these instances to &lt;code&gt;random_int()&lt;/code&gt; instead of &lt;code&gt;mt_rand()&lt;/code&gt;. So the Configurator docs are wrong, and this is the recommended way to generate random integers.&lt;/p&gt;

&lt;p&gt;It's these kinds of surprises that keep this from being a straightforward process. On to the rules for 7.1.&lt;/p&gt;

&lt;h2&gt;
  
  
  Property and Method Visibility
&lt;/h2&gt;

&lt;p&gt;Running the non-risky rules for PHP 7.1 is up next. Same as before but the ruleset is &lt;code&gt;@PHP71Migration&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This flags only one rule violation: visibility_required which tells me class properties and methods must have visibility declared. I'm going to take the easy road here and just let them all be defaulted to public because any that should be private or protected are already declared as such. So I'll let the fixer do it for me and remove the dry-run flag.&lt;/p&gt;

&lt;p&gt;My smoke-test reveals a new deprecation error appearing in the application:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; cBase has a deprecated constructor&lt;/code&gt;. I'll go in and fix this to a proper constructor.&lt;/p&gt;

&lt;p&gt;Onward to the risky ruleset for 7.1.&lt;/p&gt;

&lt;h2&gt;
  
  
  Void Return Types
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php-cs-fixer fix &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--rules&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;@PHP71Migration:risky,-declare_strict_types &lt;span class="nt"&gt;--verbose&lt;/span&gt; &lt;span class="nt"&gt;--dry-run&lt;/span&gt; &lt;span class="nt"&gt;--using-cache&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;no &lt;span class="nt"&gt;--allow-risky&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This time we get quite a few pages flagged for the rule void_return. Looking this up in the Configurator shows that it's a suggestion to add a void return type to methods and functions if not already specified.&lt;/p&gt;

&lt;p&gt;Return types are optional in PHP, and this application is discontinued anyway. I've decided to just leave the return types out. It's interesting to note however, if you wanted to execute this fix, PHP CS Fixer will actually check into the functions and methods to see if there are any non-empty return statements before adding the void return type. So the fixer is doing some intelligent analysis before just changing things on you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Heredoc
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php-cs-fixer fix &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--rules&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;@PHP73Migration &lt;span class="nt"&gt;--verbose&lt;/span&gt; &lt;span class="nt"&gt;--using-cache&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;no &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This next rule set again flagged only one issue. I'm getting lucky here. The heredoc_indentation rule was complaining about 3 files. This would have been an easy fix had I just let the fixer do it. But I tried to fix it manually so that I could also learn what I was doing wrong. Well that led me down a rabbit hole of trying to fathom what the fixer was complaining about.&lt;/p&gt;

&lt;p&gt;It turns out that it didn't like it if my heredoc text was indented more than 4 spaces beyond the line that begins the string. This seems to be a style choice enforced by the fixer. And doesn't allow me to indent it under the assignment operator (=) like I prefer.&lt;/p&gt;

&lt;p&gt;There is no 'risky' ruleset for 7.3.&lt;/p&gt;

&lt;h2&gt;
  
  
  Manual Look at 7.2
&lt;/h2&gt;

&lt;p&gt;Since there was no ruleset for 7.2. I'll have a look at the PHP &lt;a href="https://www.php.net/manual/en/migration72.php" rel="noopener noreferrer"&gt;documentation for 7.2&lt;/a&gt; and see if anything catches my eye. I'm looking specifically at backward incompatible or deprecation changes.&lt;/p&gt;

&lt;p&gt;There are quite a few gotchas in these lists. Things like the &lt;code&gt;create_function()&lt;/code&gt; and &lt;code&gt;each()&lt;/code&gt; functions being deprecated, and a bunch of other things. Searched my codebase for a few of these, and didn't find anything. The only real concern is that the &lt;code&gt;count()&lt;/code&gt; function no longer accepts a value that isn't countable. I use this function everywhere, and don't do an &lt;code&gt;is_countable()&lt;/code&gt; check before hand. I assume my values I'm passing to it are always going to be set, but this is a prime example of when a testsuite for this project would be super useful. I'm going to have to just hope that my manual test covers everything (not likely). I'll monitor the error logs just in case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Section Wrap Up
&lt;/h2&gt;

&lt;p&gt;If you wish to run ALL of the rules that we covered in this section, here is a command with everything combined:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php-cs-fixer fix &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--rules&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;full_opening_tag,no_closing_tag,@PHP70Migration,@PHP71Migration,@PHP70Migration:risky,@PHP71Migration:risky,@PHP73Migration &lt;span class="nt"&gt;--verbose&lt;/span&gt; &lt;span class="nt"&gt;--dry-run&lt;/span&gt; &lt;span class="nt"&gt;--using-cache&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;no &lt;span class="nt"&gt;--allow-risky&lt;/span&gt;:yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to fix them one at a time, you can add the &lt;code&gt;--stop-on-violation&lt;/code&gt; flag to the command.&lt;/p&gt;

&lt;p&gt;The migration rules for PHP CS Fixer are not 100% exhaustive. But they are a helpful tool to cover many of your bases. I still do a read through of all the backward incompatible and deprecation changes in all the versions between 5.6 and 7.3, and scan my codebase for them.&lt;/p&gt;

&lt;p&gt;In my next post I'll talk about using the fixer for checking PSR1 and 2 compliance. We'll then look at using PHP Code Sniffer (phpcs) to do even more code analysis.&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
&lt;a href="https://blog.syntaxseed.com/legacy-php-application-code-analysis-with-php-cs-fixer/" rel="noopener noreferrer"&gt;Originally Published on Blog.SyntaxSeed.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>legacycode</category>
      <category>codeanalysis</category>
      <category>maintenance</category>
    </item>
    <item>
      <title>Legacy PHP Application Tour &amp; Upgrade</title>
      <dc:creator>SyntaxSeed (Sherri W)</dc:creator>
      <pubDate>Wed, 23 Oct 2019 19:27:36 +0000</pubDate>
      <link>https://dev.to/syntaxseed/legacy-php-application-tour-upgrade-3a9b</link>
      <guid>https://dev.to/syntaxseed/legacy-php-application-tour-upgrade-3a9b</guid>
      <description>&lt;p&gt;The process of migrating my applications from PHP 5.6 -&amp;gt; 7.3 has been a long one – mainly due to limited time to work on it, and additional tasks being added to the migration list. But I’ve finally made it through the low hanging fruit of easy client sites and am now migrating the first project with a significant amount of back end PHP code. In this case, it’s a legacy CMS I wrote &lt;strong&gt;14+ years&lt;/strong&gt; ago called LampLight Content Manager.&lt;/p&gt;

&lt;p&gt;I wrote LampLight back when WordPress was still a bit complex for some of my customers, and it was also a time of frequent security issues and hacked sites bogging down the WP ecosystem. Today it’s a much different beast and my new projects which need a CMS default to WordPress.&lt;/p&gt;

&lt;p&gt;Anyway check out this beauty:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fw08vehek1q37mu1qz05u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fw08vehek1q37mu1qz05u.png" alt="LampLight Screenshot"&gt;&lt;/a&gt;&lt;br&gt;
LampLight Content Manager. Circa 2005.&lt;/p&gt;

&lt;p&gt;The buttons along the top represent toggle-able modules such as Articles, Gallery, Polls, etc, that I could enable or disable based on the client’s needs. I had HTML pages ready to drop into the website that could load static articles or a list of them. The editor bar inserts BBCodes because this pre-dates robust rich text editors that I liked enough. Something that less tech-savvy customers could use without creating a nested html mess and didn’t generate garbage markup.&lt;/p&gt;

&lt;p&gt;All in all LampLight has served me well. A couple clients are still using it, and my own company website is still eating this dogfood so to speak. It’s held up well over time, and even received a dashboard design refresh along with a theme switcher several years ago. But LampLight was built for PHP 5.3 and then migrated ages ago to 5.6. And there it sat until today. Let’s have a look deeper and go through my migration process! We’ll clean it up, get it working locally for the first time and migrate to PHP 7.3. (To clarify, this is still a discontinued project, but I need to keep it working for my clients still using it.) Oddly I’m still a bit proud of this piece of software. Nothing else I’ve written has been so useful, stable, or generated so many sales. I’ll be sad to see it go.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code Overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fbcfu636ed6mvss1qidwd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fbcfu636ed6mvss1qidwd.png" alt="LampLight Files"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code is a mix of object oriented and procedural. There’s no auto-loading just a few includes. Configuration is pretty organized and there are feature toggles for modules. The front end uses an earlier version of my &lt;a href="https://github.com/syntaxseed/templateseed" rel="noopener noreferrer"&gt;TemplateSeed PHP view library&lt;/a&gt;. Markup is mostly XHTML and styles use CSS, though at the time I didn’t know how to configure paths properly in CSS image URLs so the CSS file is PHP. Yikes.&lt;/p&gt;

&lt;p&gt;I use function libraries and custom plugins to reuse code. Even today, adding features is quite simple because everything is vanilla PHP.&lt;/p&gt;

&lt;p&gt;It uses a MySQL database for storage and I have a db class which wraps the mysqli functions for at least a small layer of abstraction. Database migrations are non-existent, just a big SQL file to initialize the database. I write my queries in raw SQL but all parameters are properly escaped with built in SQL escape functions. This is how we did it back then kids!&lt;/p&gt;

&lt;p&gt;Deployments are just a copy of the files via SFTP to a staging server for testing and review by the client. Then SFTP again to live. SQL changes were versioned so when I promoted a new version I would run the SQL alter table queries for that version. I can’t recall this ever biting me… I was veeeery careful.&lt;/p&gt;

&lt;p&gt;I have never had this application working on my local development machine. I would FTP changes to a hidden sub-directory and use that to preview my changes. This meant I got really good at writing a lot of code before having to actually see what it does. I’ve struggled with what I think is my ISP throttling FTP traffic and in the evenings it’s super slow, so I do a lot of writing code without many previews. The good news though, is that part of the process this week is getting it working locally – yay for instant results!&lt;/p&gt;

&lt;p&gt;Now, enough of a tour, let’s get to work!&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Run It Locally
&lt;/h2&gt;

&lt;p&gt;I created a new private Git repo and copied all the site files into it from their old home in Mercurial at BitBucket. I didn’t bother migrating the history this time because I’m breaking it out of a repo that contains several small personal sites, and re-organizing things so decided to go for a fresh start.&lt;/p&gt;

&lt;p&gt;Moved all the actual public site files into a public/ directory, cd in there and run it via the built in PHP webserver. And voila!! A ton of errors!&lt;/p&gt;

&lt;p&gt;Working my way through, I made several small fixes to get at least the homepage and a cursory click through to be error free:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a local MySQL database and set up the tables.&lt;/li&gt;
&lt;li&gt;Create copies of my config files – rename them &lt;code&gt;config-PRODUCTION.php&lt;/code&gt; and edit the originals for localhost.&lt;/li&gt;
&lt;li&gt;Replace absolute paths in the configs with something along the lines of: &lt;code&gt;define("DOC_ROOT", dirname(__FILE__)."/");&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Replace the deprecated __autoload() function with spl_autoload_register().&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Step 2: Pretty URLs without Mod_Rewrite
&lt;/h2&gt;

&lt;p&gt;The first real issue, was that using the built in PHP webserver means that my .htaccess file is not used and therefore my mod_rewrite rules to handle pretty URLs are not executed. On an Apache webserver this is used (.htaccess):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RewriteEngine On

# Test that the URL isn't pointing to a real dir or file:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# It's a pretty url, so rewrite index.php/URL to the url get param:
RewriteRule ^(.*)$ index.php?url=$1 [PT,L]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the built in PHP webserver means that the url GET parameter is never set. So my bootstraping step now needs to check if it’s empty and try to use the PATH_INFO server variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Grab our passed URL parameters.&lt;/span&gt;
&lt;span class="nv"&gt;$url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_GET&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'url'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'PATH_INFO'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;ltrim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$urlArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$urlArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;explode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few more small adjustments and it works! It’s running on localhost, pulling data from the local database, and I can even log into LampLight.&lt;/p&gt;

&lt;p&gt;But I’m running PHP 7.3 locally! Why isn’t it blowing up?&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: PHP 7 Errors
&lt;/h2&gt;

&lt;p&gt;Other than the &lt;code&gt;__autoload()&lt;/code&gt; problem, the only other real issue is a few uses of &lt;code&gt;count()&lt;/code&gt; on null or non countable input. These were trivial to fix mainly by checking for null first. And that was mainly it! Apparently this project isn’t too fancy and it sticks to very core language features.&lt;/p&gt;

&lt;p&gt;That isn’t to say that I’m done though. The code is still a mess, and hasn’t been tested beyond a cursory click through. And sadly no, I don’t have a test-suite for this project. So in the next post, I’ll get into the meat of this process by using some code analysis tools to clean things up and identify errors.&lt;/p&gt;

&lt;p&gt;This should be fun, see you next time!&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
&lt;a href="http://blog.syntaxseed.com/legacy-php-application-tour-upgrade/" rel="noopener noreferrer"&gt;Originally Published on Blog.SyntaxSeed.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>maintenance</category>
      <category>codeanalysis</category>
      <category>legacycode</category>
    </item>
    <item>
      <title>Decision Time: PHP Framework Dilemma</title>
      <dc:creator>SyntaxSeed (Sherri W)</dc:creator>
      <pubDate>Wed, 11 Sep 2019 17:56:53 +0000</pubDate>
      <link>https://dev.to/syntaxseed/decision-time-php-framework-dilemma-4fl4</link>
      <guid>https://dev.to/syntaxseed/decision-time-php-framework-dilemma-4fl4</guid>
      <description>&lt;p&gt;My freelance business has grown, and reached a critical decision point for my future development. I've been puzzling over this for a while - why not puzzle it out in public!?&lt;/p&gt;

&lt;p&gt;I need to pick a PHP framework. Or maybe not pick one. But my dilemma is kind of unusual. &lt;strong&gt;I'd love the opinions of other experienced PHP devs!&lt;/strong&gt; But hear me out, my situation is a bit unique.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unhelpful Metrics
&lt;/h2&gt;

&lt;p&gt;Extensive research has given me endless comparisons of Laravel vs Symfony &amp;amp; others, using completely useless (to me) metrics like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Number of GitHub stars.&lt;/li&gt;
&lt;li&gt;Google search popularity.&lt;/li&gt;
&lt;li&gt;Job postings.&lt;/li&gt;
&lt;li&gt;Number of StackOverflow questions.&lt;/li&gt;
&lt;li&gt;Millisecond differences in speed.&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These comparisons aren't helpful. Let me explain why.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Situation
&lt;/h2&gt;

&lt;p&gt;I build websites &amp;amp; web applications for small to medium sized businesses. Most start as a basic website with a contact form, Google Map, and that's it. Many never grow past this. Some eventually add custom dynamic elements. Say a work-order status page. A searchable directory, etc. A few have grown bigger.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;But, and this is key&lt;/em&gt;&lt;/strong&gt;... I also provide hosting, so ongoing maintenance is on me. I don't deliver a project &amp;amp; wash my hands of it. I make future text changes, fix bugs, add things &amp;amp; &lt;strong&gt;keep it running&lt;/strong&gt; - for sometimes many, many years. My oldest PHP project in production is over 10 years old!&lt;/p&gt;

&lt;p&gt;Over time I will end up with &lt;em&gt;DOZENS&lt;/em&gt; of these projects to take care of.&lt;/p&gt;

&lt;p&gt;I don't have the luxury of one, beautiful application to keep front-of-mind.&lt;/p&gt;

&lt;p&gt;And so, stability over time is a key. Easy upgrades are key. This is why WordPress replaced my internal CMS for clients who fit that use-case: one-click upgrades baby! That's gold.&lt;/p&gt;

&lt;p&gt;Until recently I was using a simple, custom MVC framework that I built. Most of my existing projects are on that. But it's over 8 years old, pre-Composer, and time for a new direction. To give that old workhorse some credit though- it has needed almost zero updates over that time (likely due to stagnating on PHP v 5.6).&lt;/p&gt;

&lt;p&gt;I have a few months of experience &amp;amp; learning with Laravel, it's nice. But ongoing updates are a concern. Backward compatibility isn't a priority for Laravel. And it's overkill for 90% of what I do.&lt;/p&gt;

&lt;p&gt;I've built a few things with SlimPHP.&lt;/p&gt;

&lt;p&gt;I'm intrigued by Symfony because it starts as a micro-framework &amp;amp; grows with you. Awesome!&lt;/p&gt;

&lt;p&gt;I'm also considering sticking a few stable Composer packages together for a light version of a 'framework' that will cover all but my few large projects. Maybe Slim is exactly that?&lt;/p&gt;

&lt;p&gt;Maybe 90% of what I do doesn't need a framework at all.&lt;/p&gt;

&lt;p&gt;It all boils down to not wanting to regret my choice 10 years from now. My youngest child starts school next year &amp;amp; when that happens I'll be throwing my efforts into my business full time. Between now &amp;amp; then I want my ducks in a row &amp;amp; to do the necessary learning.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR - My Priorities
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;PHP based.&lt;/li&gt;
&lt;li&gt;Stability over time.&lt;/li&gt;
&lt;li&gt;Well documented &amp;amp; clear upgrade process.&lt;/li&gt;
&lt;li&gt;Grows with my needs over time.&lt;/li&gt;
&lt;li&gt;Doesn't break backward compatibility on a whim.&lt;/li&gt;
&lt;li&gt;Ok to have one option for small stuff and one for big projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Thoughts?
&lt;/h2&gt;

&lt;p&gt;Do you have experience maintaining several framework-based projects over time? What do you use? Is it painful?&lt;/p&gt;

&lt;p&gt;Am I crazy for thinking everything even needs a framework?&lt;/p&gt;

&lt;p&gt;How does your company handle the time spent maintaining &amp;amp; upgrading a client's project? Do you bill them for the time? Offer a Support Licence with a monthly fee that covers this type of work? Bundle it in the hosting fee?&lt;/p&gt;

&lt;p&gt;Thanks everyone!&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
&lt;a href="http://blog.syntaxseed.com/decision-time-php-framework-dilemma/"&gt;Originally Published on Blog.SyntaxSeed.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>laravel</category>
      <category>symfony</category>
      <category>php</category>
    </item>
    <item>
      <title>Migrating Mercurial Repos To Git</title>
      <dc:creator>SyntaxSeed (Sherri W)</dc:creator>
      <pubDate>Fri, 06 Sep 2019 15:31:01 +0000</pubDate>
      <link>https://dev.to/syntaxseed/migrating-mercurial-repos-to-git-23ee</link>
      <guid>https://dev.to/syntaxseed/migrating-mercurial-repos-to-git-23ee</guid>
      <description>&lt;p&gt;In August 2019, BitBucket - a popular cloud source code hosting and project management service run by Atlassian - announced that it was &lt;a href="https://bitbucket.org/blog/sunsetting-mercurial-support-in-bitbucket" rel="noopener noreferrer"&gt;dropping support for Mercurial repositories&lt;/a&gt;. &lt;a href="https://www.mercurial-scm.org/" rel="noopener noreferrer"&gt;Mercurial&lt;/a&gt; is a distributed source control management tool similar to, but less popular than Git.&lt;/p&gt;

&lt;p&gt;This move isn't surprising. Mercurial has lost the popularity war with Git and BitBucket claims that less than 1% of new repositories on their service use Mercurial. The surprising thing is that BitBucket announced that they are &lt;em&gt;deleting Mercurial repositories&lt;/em&gt; from their service as of June 2020. Leaving developers and companies who use Mercurial with less than one year to migrate.&lt;/p&gt;

&lt;p&gt;This move by BitBucket seems inevitable, but the timeline and hard-deletion that BitBucket is giving their loyal customers seems harsh. For me, I have around 25 projects that need to be migrated.&lt;/p&gt;

&lt;p&gt;Here's how to do so, in a few easy steps!&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Decide Where To Go
&lt;/h2&gt;

&lt;p&gt;Options abound! If you want to keep your repos on Mercurial, then you do have other hosting options including SourceHug, SourceForge, CodeBase and more. The Mercurial website has a full &lt;a href="https://www.mercurial-scm.org/wiki/MercurialHosting" rel="noopener noreferrer"&gt;list of options for Mercurial hosting&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You might want to give serious thought to switching to Git. &lt;br&gt;
Detailed Git tutorials are everywhere online and learning the basics is not too hard. For me, I was already learning and using Git, so this transition was a no-brainer. Since I'm unhappy with BitBucket in general, and this new issue doesn't help, I've decided to move my projects away from BitBucket. At this time I'm keeping my Open Source projects on &lt;a href="https://github.com/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, and my private projects will be on &lt;a href="https://about.gitlab.com/" rel="noopener noreferrer"&gt;GitLab&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;For the purposes of this tutorial, I'll be teaching you how to switch to Git.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Create A New Git Repo
&lt;/h2&gt;

&lt;p&gt;First, using the tools on the cloud service where you will host your Git repos, create a new empty repo. Don't initialize it with a README file if that option is offered. Give some thought to how you want to organize and name your projects because this can be a pain to change later. Some services let you sort repos into groups, projects, or workspaces. Now is a good time to think about how you'll want to sort them when you have a ton of projects in the future. Don't just put them all in the root group.&lt;/p&gt;

&lt;p&gt;Make note of the SSL url to the repo. For GitLab this looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git@gitlab.com:username/repo-name.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Install Fast Export
&lt;/h2&gt;

&lt;p&gt;There is an awesome tool called &lt;a href="https://github.com/frej/fast-export" rel="noopener noreferrer"&gt;Fast Export&lt;/a&gt; for converting Mercurial repositories to Git. Create a directory on your development machine where you want to install Fast Export. Such as &lt;code&gt;/home/tools/fast-export/&lt;/code&gt;. From a terminal in that directory, clone the Fast Export tool with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/frej/fast-export.git .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you are using Mercurial version &amp;lt; 4.6 and you get a "revsymbol not found" error, either update Mercurial, or use an older version of Fast Export by running this in the &lt;code&gt;fast-export&lt;/code&gt; directory: &lt;code&gt;&lt;br&gt;
git checkout tags/v180317&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  4. Prepare New Local Repo
&lt;/h2&gt;

&lt;p&gt;Create a local directory where you will keep the new Git repo we are going to create with Fast Export. Initialize a new Git repo in there. &lt;em&gt;Note that terminal commands may vary if you are on Windows.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir /home/repos/git/my-project/
cd $_
git init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Use Fast Export to Convert
&lt;/h2&gt;

&lt;p&gt;First make sure you have all the latest changes pulled into your local copy of the Mercurial repo. Then, from inside the newly initialized Git directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/home/tools/fast-export/hg-fast-export.sh -r /home/repos/mercurial/my-project/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This runs the fast export shell script on the Mercurial repo. You'll see some nice output from Fast Export that looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fdvt190e8k2i1ef3ekd28.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fdvt190e8k2i1ef3ekd28.png" alt="Command line output from Fast Export with stats."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, checkout the HEAD commit like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When it's done, make sure to look at the hidden files and remove any Mercurial specific ones like &lt;code&gt;.hgignore&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Connect To Remote
&lt;/h3&gt;

&lt;p&gt;Connect the local Git repo to your new cloud hosted Git repo by setting the upstream SSH URL that you made note of earlier. In my case this looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git remote add origin git@gitlab.com:username/repo-name.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you haven't already, set up an SSH Key for connecting to your hosting service. I strongly recommend this over username/password authentication. &lt;a href="https://docs.gitlab.com/ee/ssh/" rel="noopener noreferrer"&gt;GitLab's documentation on SSH Keys&lt;/a&gt; is very complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Push The New Repo To The Remote Repository
&lt;/h2&gt;

&lt;p&gt;Push the local Git repo to the remote. If you put a password on your SSH Key (recommended) then you will be prompted for it. To make sure you get everything up there, do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push -u origin --all
git push -u origin --tags
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When these are done, visit the remote repo on GitLab or whichever service you chose, via your web browser. Confirm that the code and commit history is there. You may want to make a small local edit, then commit and push it to test it's all working.&lt;/p&gt;

&lt;p&gt;These steps should work for a straightforward Mercurial repository. If you have branch names that don't convert to Git, or if you want the author information converted, there are ways to do this, just check out the &lt;a href="https://github.com/frej/fast-export#readme" rel="noopener noreferrer"&gt;Fast Export Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus! Fix Line Endings
&lt;/h2&gt;

&lt;p&gt;If like me, you received a bunch of warnings that your project has Windows style line endings (CRLF) and that Git was replacing them with Linux style endings (LF), you might want to ensure your local copy has the proper endings too. Many of my projects were originally created on a Windows machine but I now work on Linux, so these mixed endings have been everywhere. To make sure your local matches the remote, you can reset your local to what's now in Git. First make sure everything is pushed to the remote successfully, then do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git rm --cached -r .
git reset --hard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This removes everything locally and then resets your working tree to the last commit. You'll lose the exiting working tree and staging area. If no commit is specified, then HEAD is assumed. Make sure your editor is using the correct line endings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;That's it! Once you get this process down, migrating a Mercurial repo can take as little as 10 minutes. It's a good idea if you're new to Git, to create a sandbox repository where you can experiment and try out Git's commands. Many people like to use a GUI interface for Git as well.&lt;/p&gt;

&lt;p&gt;For me, it is a fond farewell to Mercurial. It has served me well over 10+ years of development and I'll miss its simplicity. ❤&lt;/p&gt;

&lt;p&gt;Good Luck with your own migration!&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
&lt;a href="https://blog.syntaxseed.com/migrating-mercurial-repos-to-git/" rel="noopener noreferrer"&gt;Originally Published on Blog.SyntaxSeed.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mercurial</category>
      <category>git</category>
      <category>bitbucket</category>
      <category>gitlab</category>
    </item>
    <item>
      <title>Multiple Apps on One Server With Mod-Rewrite</title>
      <dc:creator>SyntaxSeed (Sherri W)</dc:creator>
      <pubDate>Thu, 20 Jun 2019 14:18:53 +0000</pubDate>
      <link>https://dev.to/syntaxseed/multiple-apps-on-one-server-with-mod-rewrite-44k8</link>
      <guid>https://dev.to/syntaxseed/multiple-apps-on-one-server-with-mod-rewrite-44k8</guid>
      <description>&lt;p&gt;For small companies and freelance or solo developers, hosting can be an expense which adds up over time to a hefty bill. Whether you have several VPSes or shared-hosting accounts, it makes little sense to have multiple small, experimental, or low-traffic sites on their own servers. You could serve them from multiple subdomains or subdirectories, but yuck! Domains are cheap and I like the polish of having something on it's own domain once it's public.&lt;/p&gt;

&lt;p&gt;However, hosting companies usually only give you one web root directory. In the case of a VPS, sometimes provisioning them charges a small fee per 'app'. An app being a distinct project or site on it's own domain and with a separate web root directory (such as &lt;code&gt;/www/appname/html/&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Fake It Till You Make It
&lt;/h2&gt;

&lt;p&gt;Let's look at how we can use Apache's mod-rewrite module to create several fake web roots and send traffic to them based on request domain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;First, we'll assume that you already have one domain (such as example.com) pointed to your server. It is serving pages that you place in your web root.&lt;/p&gt;

&lt;p&gt;Next, park a second domain (example.net) to the same server or hosting account. I won't get into how domain parking works. This second domain should be serving the same pages in the same web root like an alias. Two domains to a single site.&lt;/p&gt;

&lt;p&gt;Then in your web root, create two directories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;site-examplecom/&lt;/li&gt;
&lt;li&gt;site-examplenet/&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And move your existing site files into the first one. Add a placeholder index.html with some text to the second one, so we will see when one or the other site is served. Now you're ready for the magic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mod Rewrite Is A Multi-tool Of Awesome
&lt;/h3&gt;

&lt;p&gt;Apache HTTP Server has a module called &lt;strong&gt;&lt;a href="https://httpd.apache.org/docs/current/mod/mod_rewrite.html"&gt;Mod_Rewrite&lt;/a&gt;&lt;/strong&gt; which is usually installed by default. Make sure you have it on your server. You can give Apache instructions via a &lt;strong&gt;.htaccess&lt;/strong&gt; file in your web root. These will affect the directory the file is in, and all subdirectories. Create an empty file named .htaccess in your web root, or edit the existing one. Don't put it in those site-* directories we created earlier.&lt;/p&gt;

&lt;p&gt;Next, put the following in that file and we'll look at what it does.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight conf"&gt;&lt;code&gt;&amp;lt;&lt;span class="n"&gt;IfModule&lt;/span&gt; &lt;span class="n"&gt;mod_rewrite&lt;/span&gt;.&lt;span class="n"&gt;c&lt;/span&gt;&amp;gt;
&lt;span class="n"&gt;RewriteEngine&lt;/span&gt; &lt;span class="n"&gt;On&lt;/span&gt;

&lt;span class="c"&gt;# Direct requests for example.COM:
&lt;/span&gt;&lt;span class="n"&gt;RewriteCond&lt;/span&gt; %{&lt;span class="n"&gt;HTTP_HOST&lt;/span&gt;} ^(?:&lt;span class="n"&gt;www&lt;/span&gt;\.)?&lt;span class="n"&gt;example&lt;/span&gt;\.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;RewriteCond&lt;/span&gt; %{&lt;span class="n"&gt;REQUEST_URI&lt;/span&gt;} !^/&lt;span class="n"&gt;site&lt;/span&gt;-&lt;span class="n"&gt;examplecom&lt;/span&gt;/
&lt;span class="n"&gt;RewriteRule&lt;/span&gt; ^(.*)$ /&lt;span class="n"&gt;site&lt;/span&gt;-&lt;span class="n"&gt;examplecom&lt;/span&gt;/$&lt;span class="m"&gt;1&lt;/span&gt; [&lt;span class="n"&gt;L&lt;/span&gt;]

&lt;span class="c"&gt;# Direct requests for example.NET:
&lt;/span&gt;&lt;span class="n"&gt;RewriteCond&lt;/span&gt; %{&lt;span class="n"&gt;HTTP_HOST&lt;/span&gt;} ^(?:&lt;span class="n"&gt;www&lt;/span&gt;\.)?&lt;span class="n"&gt;example&lt;/span&gt;\.&lt;span class="n"&gt;net&lt;/span&gt;
&lt;span class="n"&gt;RewriteCond&lt;/span&gt; %{&lt;span class="n"&gt;REQUEST_URI&lt;/span&gt;} !^/&lt;span class="n"&gt;site&lt;/span&gt;-&lt;span class="n"&gt;examplenet&lt;/span&gt;
&lt;span class="n"&gt;RewriteRule&lt;/span&gt; ^(.*)$ /&lt;span class="n"&gt;site&lt;/span&gt;-&lt;span class="n"&gt;examplenet&lt;/span&gt;/$&lt;span class="m"&gt;1&lt;/span&gt; [&lt;span class="n"&gt;L&lt;/span&gt;]

&amp;lt;/&lt;span class="n"&gt;IfModule&lt;/span&gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Mod_Rewrite takes the requested URL, and based on PCRE regular expression rules, can change the corresponding filesystem path or even rewrite to a different URL.&lt;/p&gt;

&lt;p&gt;The &amp;lt;IfModule&amp;gt; directive will ensure that the lines inside are only executed if that module exists.&lt;/p&gt;

&lt;p&gt;The first line inside is clear, it turns on the rewrite engine. No kidding.&lt;/p&gt;

&lt;p&gt;Then we have two nearly identical blocks of 3 lines led by a comment. Let's examine those 3 lines.&lt;/p&gt;

&lt;p&gt;First:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;RewriteCond&lt;/span&gt; %{&lt;span class="n"&gt;HTTP_HOST&lt;/span&gt;} ^(?:&lt;span class="n"&gt;www&lt;/span&gt;\.)?&lt;span class="n"&gt;example&lt;/span&gt;\.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;One or more &lt;strong&gt;RewriteCond&lt;/strong&gt; directives can precede a &lt;strong&gt;RewriteRule&lt;/strong&gt;. The rule will only be executed if the preceding conditions are met.&lt;/p&gt;

&lt;p&gt;This line compares the incoming http host from the request headers (base domain part of the URL) to the regular expression &lt;code&gt;^(?:www\.)?example\.com&lt;/code&gt;. The ^ symbol means 'starts with'. So we are checking if the request host begins with example.com with the &lt;code&gt;www.&lt;/code&gt; being optional and not captured to a variable. If it the host matches this regex, we move onto the next line. &lt;/p&gt;

&lt;p&gt;Second:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;RewriteCond&lt;/span&gt; %{&lt;span class="n"&gt;REQUEST_URI&lt;/span&gt;} !^/&lt;span class="n"&gt;site&lt;/span&gt;-&lt;span class="n"&gt;examplecom&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This condition checks if the request URI (the part after the host/domain) does NOT (the '!' negates the regex) start with &lt;code&gt;/site-examplecom&lt;/code&gt;. Which it will contain when we do a successful rewrite. This is important, it stops us from entering an infinite loop of doom and getting a Server 500 error.&lt;/p&gt;

&lt;p&gt;Third:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;RewriteRule&lt;/span&gt; ^(.*)$ /&lt;span class="n"&gt;site&lt;/span&gt;-&lt;span class="n"&gt;examplecom&lt;/span&gt;/$&lt;span class="m"&gt;1&lt;/span&gt; [&lt;span class="n"&gt;L&lt;/span&gt;]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And finally, if the conditions were met, we perform a substitution of the requested path (url part after the host and port). Watch out: the already mapped directories are removed. So if the .htaccess file is in the top web root you get the full URL path without the leading slash. If the .htaccess file was in a &lt;code&gt;test/&lt;/code&gt; sub directory of the web root, you'd only be matching the pattern against the part of the URL path &lt;em&gt;after&lt;/em&gt; &lt;code&gt;test/&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;(.*)&lt;/code&gt; pattern grabs everything from the beginning ('^') to the end ('$') of the URL path, saves it in the variable &lt;code&gt;$1&lt;/code&gt;, then sticks it after &lt;code&gt;/site-examplecom/&lt;/code&gt;. The &lt;code&gt;[L]&lt;/code&gt; flag means to stop processing rules for this request if this one was executed.&lt;/p&gt;

&lt;h3&gt;
  
  
  High-Level Look
&lt;/h3&gt;

&lt;p&gt;We have this block of two conditions and one rule, duplicated for our two 'apps'. This is the process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If it's the right http host.&lt;/li&gt;
&lt;li&gt;And if it's not already requesting our fake &lt;code&gt;site-*&lt;/code&gt; app root.&lt;/li&gt;
&lt;li&gt;Then append &lt;code&gt;site-example*/&lt;/code&gt; to the front of the URL path.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that's it. You should now see the two different sites if you visit the different domains. You can add another parked domain, subdirectory and block of rewrite directives to add another 'app'.&lt;/p&gt;

&lt;h3&gt;
  
  
  Considerations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Faking web roots has some drawbacks. Your apps are not isolated from one another. In theory they could mess with each other, and a vulnerability in one affects the others.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your host might have terms against doing this. Though I don't see why you wouldn't be able to harness the power of the tools at your disposal.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You should keep your applications' databases separate. This will make moving and migrating apps/sites easier, and avoid collisions with tables.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make sure that any of your code that deals with filesystem paths, takes into account that the url path and filesystem path won't match.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using .htaccess files slows Apache down a little bit. If you have access to the main httpd configuration for the server, you should set these rules in a &amp;lt;directory&amp;gt; block there instead.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Multiple sites on one server or hosting account can eat up system resources quickly. This is why I only recommend this for small projects with very low traffic. Sites that don't warrant their own server/hosting yet.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Fun Extras
&lt;/h3&gt;

&lt;p&gt;There is an &lt;a href="https://htaccess.madewithlove.be/"&gt;excellent tool for testing Mod_Rewrite rules&lt;/a&gt; found on the madewithlove website.&lt;/p&gt;

&lt;p&gt;If you'd like to strip the www off of requests and ensure that your site is only visited via the naked domain, add this (applies to all domains) before your other rules (the &lt;code&gt;R=301&lt;/code&gt; flag tells browsers and search engines that this is a permanent redirect, consider leaving it off till you're happy that it's working):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="c"&gt;# Remove the www:
&lt;/span&gt;&lt;span class="n"&gt;RewriteCond&lt;/span&gt; %{&lt;span class="n"&gt;HTTP_HOST&lt;/span&gt;} ^&lt;span class="n"&gt;www&lt;/span&gt;\.
&lt;span class="n"&gt;RewriteRule&lt;/span&gt; ^(.*)$ &lt;span class="n"&gt;https&lt;/span&gt;://%{&lt;span class="n"&gt;HTTP_HOST&lt;/span&gt;}/$&lt;span class="m"&gt;1&lt;/span&gt; [&lt;span class="n"&gt;R&lt;/span&gt;=&lt;span class="m"&gt;301&lt;/span&gt;,&lt;span class="n"&gt;L&lt;/span&gt;]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  That's All Folks
&lt;/h3&gt;

&lt;p&gt;I hope this little tutorial was helpful. I learned a lot writing it, and while I've been using this for many years, I'm also curious whether anyone has any gotchas I should consider or improvements I could make. Thanks for reading!&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
&lt;a href="https://blog.syntaxseed.com/multiple-apps-on-one-server-with-mod-rewrite/"&gt;Originally Published on Blog.SyntaxSeed.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>apache</category>
      <category>modrewrite</category>
      <category>webdev</category>
      <category>http</category>
    </item>
  </channel>
</rss>
