Back to All Posts

Formatting PHP More Efficiently with a Bash Function

For quite some time now, I’ve been working with a PHP application that, up until recently, had no clearly-defined coding standards in place. At some point, the decision was made to enforce PSR-2, and to do so at an incremental level. When a file is touched, format to PSR-2.

To do this in the command line, I’ve been using PHP-CS-Fixer. It’s pretty straightforward in how it works. Call the command, pass a file, specify a standard:

php-cs-fixer /path/to/file.php --rules=@PSR2

But fairly quickly, typing all those characters added up, and it was made more difficult by the fact that I need to hold SHIFT + 2 in order to crank out an @. Woe is me!

Wrap that Complexity in a Function

To remedy this a bit, I turned to writing a simple Bash function to wrap up some of the work I had been doing over and over. It was a good move. Here’s how it went:

In my ~./zshrc file, save the following function declaration. If you’re not using Oh My ZSH, this would be placed in your ~/.bashrc file, or the configuration file for whatever shell you’re using.

function fphp {
    php-cs-fixer fix $1 --rules=@PSR2
}

To actually use the function, you’ll need to reload your configuration file.

source ~/.zshrc

After that, you’re ready to run! Instead of specifying a long command name, pasting in the file path, and setting a standard, you can just run this to get the same result.

fphp /path/to/file.php

Handling Multiple Paths

That’s much better, but sometimes, you might want to format several different files by file path at once. Using the version of PHP-CS-Fixer that I am (2.14.0), it’s technically possible to do this, but requires some extra work I didn’t want to deal with. Without doing that extra work, the following error is thrown:

php-cs-fixer /path/to/file.php /path/to/some/other/file.php --rules=@PSR2
In ConfigurationResolver.php line 579:
For multiple paths config parameter is required.

Thankfully, since the functionality we want is all wrapped up in a function, it’s relatively easy to beef that sucker up to handle multiple paths as we provide them. Basically, take whatever arguments our function is given and run the same command on each of them.

function fphp {
    for filePath in "$@"
    do
        php-cs-fixer fix $filePath --rules=@PSR2
    done
}

Run source ~/.zshrc, and now we can easily format multiple files at once:

fphp /path/to/file.php /path/to/some/other/file.php

We’ve Only Bashed the Surface

Obviously, my use case here is pretty specific, and there are a bazillion other ways Bash funcification (just coined that; it better stick) can optimize your command line workflow. As a top-of-mind example, my teammate and buddy Buddy Reno has written about using them to awesomely overhaul how you use Git in your projects.

Whatever your entry point has been or will be, do your part and be generous with your findings! To start, if you’ve got a Bash-related tip that’s been helpful to you in the past, share it here!

2022-02-22-send-an-http-request-on-page-exit

A post on CSS Tricks exploring why HTTP requests sent during page navigation are at risk of abandonment, as well as options available to prevent it from happening.

2022-06-15-maps-store-objects-by-reference

No matter how many times I revisit it, I have pretty consistent track record of being tripped up by how JavaScript assigns values to variables.


## Primitives: Assigned by Value


Primitive values (numbers, strings, etc.) are assigned by _value,_ meaning that assigning one variable to another variable assigned to a primitive value will result in _two, distinct values_ being stored in memory. The entire _value_ is copied.


```text
const number1 = 100;const number2 = number1;// Variable / Memory Value:// number1 -> 100// number2 -> 100
```


## Objects: Assigned by Reference


Everything else (objects, including functions, arrays, etc.) are assigned by _reference_. Assigning a newly created object to a variable is actually creating a _reference_ to that object’s location in memory. Any further variable assignments will also point to that exact same location.


```text
const object1 = { someProperty: 'some value' };const object2 = object1;// Variable / Memory Value:// object1 -> { someProperty: 'some value' }// object2 -> object1
```


And that’s why things like this work. If you mess with the properties of an object — no matter which variable is referencing it — that central value in memory will be changed, impacting every variable pointing to it.


```text
let object1 = { someProperty: 'some value' };let object2 = object1;let object3 = object2;let object4 = object3;let object5 = object4;object5.someProperty = 'some OTHER value!';console.log(object1);// { someProperty: 'some OTHER value!' }
```


## A Map() Follows the Same Rules


This is a pretty fundamental concept in JavaScript, but that didn’t stop me from forgetting about it while dealing with a `Map()`. Just like a regular, old variable, a value inside a Map() is stored differently depending on the value’s type — primitive or otherwise. From [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get):


> If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Map object.


In my case, I was working with somthing like this (highly contrived):


```html
const aMap = new Map();const anObj = {  name: 'Alex'}aMap.set('a', anObj);aMap.set('b', anObj);aMap.set('c', anObj);aMap.get('c').name = 'Bob';console.table(Array.from(aMap.entries()));
```


While I was intending to modify the `name` only by on the `a` key, the results prints as follows:


```html
| (index) |  0  |        1        |-----------------------------------|    0    | 'a' | { name: 'Bob' } ||    1    | 'b' | { name: 'Bob' } ||    2    | 'c' | { name: 'Bob' } |
```


Bob is everywhere. In hindsight, this is no surprise. _Primitives by value, objects by reference._ If I want these values to be updated independently, the answer is to duplicate the object, reserving it a new, distinct place in memory:


```diff
const aMap = new Map();const anObj = {  name: 'Alex'}- aMap.set('a', anObj);+ aMap.set('a', {...anObj});- aMap.set('b', anObj);+ aMap.set('b', {...anObj});- aMap.set('c', anObj);+ aMap.set('c', {...anObj});aMap.get('c').name = 'Bob';console.table(Array.from(aMap.entries()));
```


And with that, you’re released to update properties freely:


```html
| (index) |  0  |        1         |------------------------------------|    0    | 'a' | { name: 'Alex' }  ||    1    | 'b' | { name: 'Alex' } ||    2    | 'c' | { name: 'Bob' } |
```


Just one “Bob,” as desired.


## Only a Matter of Time


Stay tuned for another post basically covering the same concept within another context after it inevitably trips me up again.

Alex MacArthur is a software engineer working for Dave Ramsey in Nashville-ish, TN.
Soli Deo gloria.

Get irregular emails about new posts or projects.

No spam. Unsubscribe whenever.
Leave a Free Comment

1 comments
  • Andrey

    Please correct the path error " ~./zshrc" in the "Wrap This Complexity in a Function" section, it should be " ~/.zshrc"
    Thank you for the article.