{"id":16214,"date":"2023-09-15T13:00:59","date_gmt":"2023-09-15T16:00:59","guid":{"rendered":"https:\/\/deliciousbrains.com\/?p=16214"},"modified":"2024-04-10T10:58:17","modified_gmt":"2024-04-10T13:58:17","slug":"refactoring-php-code-better-readability","status":"publish","type":"post","link":"https:\/\/deliciousbrains.com\/refactoring-php-code-better-readability\/","title":{"rendered":"Examples of Refactoring PHP Code for Better&nbsp;Readability"},"content":{"rendered":"<p>Refactoring code is when you restructure existing code without changing its external behavior. Basically your aim is to make \u201cbad\u201d code better without changing the underlying functionality, and one of the key ways you can do this is by making sure human beings can understand it. In this article, we\u2019ll look at some of the refactoring techniques you can use to make sure your code is clear, human-readable, and simpler to maintain.<\/p>\n\n<p>It should be noted that there are cases when the time spent refactoring would be better spent rewriting the code from scratch. Minor tweaks and refactors can improve maintainable code, but gutting over 50% of your code may mean a rewrite is more cost-effective. Refactoring incrementally over time avoids crossing this threshold and makes that part of the code easier to maintain in the future. A previous version of this article was written by Gilbert Pellegrom and published in 2016. This version largely retains his original code examples.<\/p>\n\n<h2>Refactoring for Simplicity<\/h2>\n\n<p>There are a few principles you\u2019ll hear about again and again when it comes to refactoring. The YAGNI (&#8220;You Aren&#8217;t Gonna Need It&#8221;) principle suggests focusing on implementing only current requirements without anticipating hypothetical future needs that may never materialize. Closely related is KISS (&#8220;Keep It Simple, Stupid&#8221;), which emphasizes designing systems simply and intuitively. These are handy principles, but we\u2019ll start by keeping things DRY.<\/p>\n\n<h3 id=\"dont-repeat-yourself\">Don\u2019t Repeat Yourself (DRY)<\/h3>\n\n<p>Probably <em>the<\/em> most popular programming principle you\u2019re likely to hear is \u201cDon\u2019t Repeat Yourself\u201d (DRY). If you find yourself duplicating the same code a couple of times, then you should probably encapsulate the functionality in its own class or function and use said class or function to avoid repetition. This means you only need to fix the code in one place when the inevitable bug arises months down the line.<\/p>\n\n<p>A good example of this is when different but similar classes require some of the same functionality. The example below defines two classes, <code>AwesomeAddon<\/code> and <code>EvenMoreAwesomeAddon<\/code>, with the code duplicated in each class.<\/p>\n\n<pre><code>&lt;?php\n\nclass AwesomeAddon {\n\n    private $settings;\n\n    public function __construct( $settings ) {\n        $this-&gt;set_settings( $settings );\n    }\n\n    protected function set_settings( $settings ) {\n        if ( ! is_array( $settings ) ) {\n            throw new \\Exception( 'Invalid settings' );\n        }\n\n        $this-&gt;settings = $settings;\n    }\n\n    protected function do_something_awesome() {\n        \/\/...\n    }\n\n}\n\nclass EvenMoreAwesomeAddon {\n\n    private $settings;\n\n    public function __construct( $settings ) {\n        $this-&gt;set_settings( $settings );\n    }\n\n    protected function set_settings( $settings ) {\n        if ( ! is_array( $settings ) ) {\n            throw new \\Exception( 'Invalid settings' );\n        }\n\n        $this-&gt;settings = $settings;\n    }\n\n    protected function do_something_even_more_awesome() {\n        \/\/...\n    }\n\n}\n<\/code><\/pre>\n\n<p>Instead of duplicating the code across two different classes, you could create a parent or <a href=\"http:\/\/php.net\/manual\/en\/language.oop5.abstract.php\">abstract class<\/a> which holds the common functionality, and then make the <code>AwesomeAddon<\/code> and <code>EvenMoreAwesomeAddon<\/code> classes to inherit from it:<\/p>\n\n<pre><code>&lt;?php\n\nabstract class Addon {\n\n    protected $settings;\n\n    protected function set_settings( $settings ) {\n        if ( ! is_array( $settings ) ) {\n            throw new \\Exception( 'Invalid settings' );\n        }\n\n        $this-&gt;settings = $settings;\n    }\n\n}\n\nclass AwesomeAddon extends Addon {\n\n    public function __construct( $settings ) {\n        $this-&gt;set_settings( $settings );\n    }\n\n    protected function do_something_awesome() {\n        \/\/...\n    }\n\n}\n\nclass EvenMoreAwesomeAddon extends Addon {\n\n    public function __construct( $settings ) {\n        $this-&gt;set_settings( $settings );\n    }\n\n    protected function do_something_even_more_awesome() {\n        \/\/...\n    }\n\n}\n<\/code><\/pre>\n\n<p>First, we declare an abstract <code>Addon<\/code> class, which captures the common code for <code>$settings<\/code> in <code>AwesomeAddon<\/code> and <code>EvenMoreAwesomeAddon<\/code>. Next, we added <code>array<\/code> type before <code>$settings<\/code> in <code>__construct<\/code> and <code>set_settings<\/code> methods, and <code>void<\/code> return type in <code>setSettings<\/code> method. This ensures we pass an array of settings when we create an instance and that function doesn&#8217;t return anything. We\u2019ve also removed the exception for when <code>$settings<\/code> is not an array, because the array type hint on <code>set_settings<\/code> method will throw an exception automatically now if anything other than an array is passed to it.<\/p>\n\n<h2 id=\"splitting-up-complex-functions\">Splitting up Complex Functions<\/h2>\n\n<p>Complex functions and methods can also lead to technical debt and hard-to-read code. One way to deal with this is to break up complicated functions into smaller chunks that are easy to understand (and test).<\/p>\n\n<blockquote>\u201cPrograms must be written for people to read, and only incidentally for machines to execute.\u201d &#8211; Harold Abelson<\/blockquote>\n\n<p>Here\u2019s an example of a complex function, a complete method for uploading a file from a WordPress site to S3 and handling pre-upload conditions, post-upload operations, and potential error situations.<\/p>\n\n<pre><code>&lt;?php\nfunction upload_attachment_to_s3( $post_id, $data = null, $file_path = null, $force_new_s3_client = false, $remove_local_files = true ) {\n    $return_metadata = null;\n    if ( is_null( $data ) ) {\n        $data = wp_get_attachment_metadata( $post_id, true );\n    } else {\n        \/\/ As we have passed in the meta, return it later\n        $return_metadata = $data;\n    }\n\n    if ( is_wp_error( $data ) ) {\n        return $data;\n    }\n\n    \/\/ Allow S3 upload to be hijacked\/canceled for any reason\n    $pre = apply_filters( 'as3cf_pre_upload_attachment', false, $post_id, $data );\n    if ( false !== $pre ) {\n        if ( ! is_null( $return_metadata ) ) {\n            \/\/ If the attachment metadata is supplied, return it\n            return $data;\n        }\n\n        $error_msg = is_string( $pre ) ? $pre : __( 'Upload aborted by filter \\'as3cf_pre_upload_attachment\\'', 'amazon-s3-and-cloudfront' );\n\n        return $this-&gt;return_upload_error( $error_msg );\n    }\n\n    if ( is_null( $file_path ) ) {\n        $file_path = get_attached_file( $post_id, true );\n    }\n\n    \/\/ Check file exists locally before attempting upload\n    if ( ! file_exists( $file_path ) ) {\n        $error_msg = sprintf( __( 'File %s does not exist', 'amazon-s3-and-cloudfront' ), $file_path );\n\n        return $this-&gt;return_upload_error( $error_msg, $return_metadata );\n    }\n\n    $file_name     = basename( $file_path );\n    $type          = get_post_mime_type( $post_id );\n    $allowed_types = $this-&gt;get_allowed_mime_types();\n\n    \/\/ Check mime type of file is in allowed S3 mime types\n    if ( ! in_array( $type, $allowed_types ) ) {\n        $error_msg = sprintf( __( 'Mime type %s is not allowed', 'amazon-s3-and-cloudfront' ), $type );\n\n        return $this-&gt;return_upload_error( $error_msg, $return_metadata );\n    }\n\n    $acl = self::DEFAULT_ACL;\n\n    \/\/ Check the attachment already exists in S3, eg., edit or restore image\n    if ( ( $old_s3object = $this-&gt;get_attachment_s3_info( $post_id ) ) ) {\n        \/\/ use existing non default ACL if attachment already exists\n        if ( isset( $old_s3object['acl'] ) ) {\n            $acl = $old_s3object['acl'];\n        }\n        \/\/ Use existing prefix\n        $prefix = dirname( $old_s3object['key'] );\n        $prefix = ( '.' === $prefix ) ? '' : $prefix . '\/';\n        \/\/ Use existing bucket\n        $bucket = $old_s3object['bucket'];\n        \/\/ Get existing region\n        if ( isset( $old_s3object['region'] ) ) {\n            $region = $old_s3object['region'];\n        };\n    } else {\n        \/\/ Derive prefix from various settings\n        if ( isset( $data['file'] ) ) {\n            $time = $this-&gt;get_folder_time_from_url( $data['file'] );\n        } else {\n            $time = $this-&gt;get_attachment_folder_time( $post_id );\n            $time = date( 'Y\/m', $time );\n        }\n\n        $prefix = $this-&gt;get_file_prefix( $time );\n\n        \/\/ Use bucket from settings\n        $bucket = $this-&gt;get_setting( 'bucket' );\n        $region = $this-&gt;get_setting( 'region' );\n        if ( is_wp_error( $region ) ) {\n            $region = '';\n        }\n    }\n\n    $acl = apply_filters( 'as3cf_upload_acl', $acl, $data, $post_id );\n\n    $s3object = array(\n        'bucket' =&gt; $bucket,\n        'key'    =&gt; $prefix . $file_name,\n        'region' =&gt; $region,\n    );\n\n    \/\/ Store acl if not default\n    if ( $acl != self::DEFAULT_ACL ) {\n        $s3object['acl'] = $acl;\n    }\n\n    $s3client = $this-&gt;get_s3client( $region, $force_new_s3_client );\n\n    $args = array(\n        'Bucket'       =&gt; $bucket,\n        'Key'          =&gt; $prefix . $file_name,\n        'SourceFile'   =&gt; $file_path,\n        'ACL'          =&gt; $acl,\n        'ContentType'  =&gt; $type,\n        'CacheControl' =&gt; 'max-age=31536000',\n        'Expires'      =&gt; date( 'D, d M Y H:i:s O', time() + 31536000 ),\n    );\n\n    $args = apply_filters( 'as3cf_object_meta', $args, $post_id );\n\n    $files_to_remove = array();\n\n    if ( file_exists( $file_path ) ) {\n        $files_to_remove[] = $file_path;\n        try {\n            $s3client-&gt;putObject( $args );\n        } catch ( Exception $e ) {\n            $error_msg = sprintf( __( 'Error uploading %s to S3: %s', 'amazon-s3-and-cloudfront' ), $file_path, $e-&gt;getMessage() );\n\n            return $this-&gt;return_upload_error( $error_msg, $return_metadata );\n        }\n    }\n\n    delete_post_meta( $post_id, 'amazonS3_info' );\n\n    add_post_meta( $post_id, 'amazonS3_info', $s3object );\n\n    $file_paths        = $this-&gt;get_attachment_file_paths( $post_id, true, $data );\n    $additional_images = array();\n\n    $filesize_total             = 0;\n    $remove_local_files_setting = $this-&gt;get_setting( 'remove-local-file' );\n\n    if ( $remove_local_files_setting ) {\n        $bytes = filesize( $file_path );\n        if ( false !== $bytes ) {\n            \/\/ Store in the attachment metadata for use by WP\n            $data['filesize'] = $bytes;\n\n            if ( is_null( $return_metadata ) ) {\n                \/\/ Update metadata with filesize\n                update_post_meta( $post_id, '_wp_attachment_metadata', $data );\n            }\n\n            \/\/ Add to the file size total\n            $filesize_total += $bytes;\n        }\n    }\n\n    foreach ( $file_paths as $file_path ) {\n        if ( ! in_array( $file_path, $files_to_remove ) ) {\n            $additional_images[] = array(\n                'Key'        =&gt; $prefix . basename( $file_path ),\n                'SourceFile' =&gt; $file_path,\n            );\n\n            $files_to_remove[] = $file_path;\n\n            if ( $remove_local_files_setting ) {\n                \/\/ Record the file size for the additional image\n                $bytes = filesize( $file_path );\n                if ( false !== $bytes ) {\n                    $filesize_total += $bytes;\n                }\n            }\n        }\n    }\n\n    if ( $remove_local_files ) {\n        if ( $remove_local_files_setting ) {\n            \/\/ Allow other functions to remove files after they have processed\n            $files_to_remove = apply_filters( 'as3cf_upload_attachment_local_files_to_remove', $files_to_remove, $post_id, $file_path );\n            \/\/ Remove duplicates\n            $files_to_remove = array_unique( $files_to_remove );\n\n            \/\/ Delete the files\n            $this-&gt;remove_local_files( $files_to_remove );\n        }\n    }\n\n    \/\/ Store the file size in the attachment meta if we are removing local file\n    if ( $remove_local_files_setting ) {\n        if ( $filesize_total &gt; 0 ) {\n            \/\/ Add the total file size for all image sizes\n            update_post_meta( $post_id, 'wpos3_filesize_total', $filesize_total );\n        }\n    } else {\n        if ( isset( $data['filesize'] ) ) {\n            \/\/ Make sure we don't have a cached file sizes in the meta\n            unset( $data['filesize'] );\n\n            if ( is_null( $return_metadata ) ) {\n                \/\/ Remove the filesize from the metadata\n                update_post_meta( $post_id, '_wp_attachment_metadata', $data );\n            }\n\n            delete_post_meta( $post_id, 'wpos3_filesize_total' );\n        }\n    }\n\n    if ( ! is_null( $return_metadata ) ) {\n        \/\/ If the attachment metadata is supplied, return it\n        return $data;\n    }\n\n    return $s3object;\n}\n<\/code><\/pre>\n\n<p>This function is quite long. The code would be cleaner, more readable, and easier to maintain if we refactored to take a more object-oriented approach where the functionalities are abstracted into methods of a class. We can make the primary function, <code>upload_attachment_to_s3<\/code>, much easier to read by abstracting every component of the task into its own method:<\/p>\n\n<pre><code>&lt;?php\nfunction upload_attachment_to_s3( $post_id, $data = null, $file_path = null, $force_new_s3_client = false, $remove_local_files = true ) {\n    $return_metadata = $this-&gt;get_attachment_metadata( $post_id );\n    if ( is_wp_error( $return_metadata ) ) {\n        return $return_metadata;\n    }\n\n    \/\/ Allow S3 upload to be hijacked\/canceled for any reason\n    $pre = apply_filters( 'as3cf_pre_upload_attachment', false, $post_id, $data );\n    if ( $this-&gt;upload_should_be_cancelled( $pre ) ) {\n        return $pre;\n    }\n\n    \/\/ Check file exists locally before attempting upload\n    if ( ! $this-&gt;local_file_exists() ) {\n        $error_msg = sprintf( __( 'File %s does not exist', 'amazon-s3-and-cloudfront' ), $file_path );\n\n        return $this-&gt;return_upload_error( $error_msg, $return_metadata );\n    }\n\n    \/\/ Check mime type of file is in allowed S3 mime types\n    if ( ! $this-&gt;is_valid_mime_type() ) {\n        $error_msg = sprintf( __( 'Mime type %s is not allowed', 'amazon-s3-and-cloudfront' ), $type );\n\n        return $this-&gt;return_upload_error( $error_msg, $return_metadata );\n    }\n\n    $s3object = $this-&gt;get_attachment_s3_info( $post_id );\n    $acl = $this-&gt;get_s3object_acl( $s3object );\n\n    $s3client = $this-&gt;get_s3client( $region, $force_new_s3_client );\n\n    $args = array(\n        'Bucket'       =&gt; $s3object['bucket'],\n        'Key'          =&gt; $s3object['key'],\n        'SourceFile'   =&gt; $s3object['source_file'],\n        'ACL'          =&gt; $acl,\n        'ContentType'  =&gt; $s3object['mime_type'],\n        'CacheControl' =&gt; 'max-age=31536000',\n        'Expires'      =&gt; date( 'D, d M Y H:i:s O', time() + 31536000 ),\n    );\n\n    $s3client-&gt;putObject( $args );\n\n    $this-&gt;maybe_remove_files( $args, $s3object );\n\n    return $s3object;\n}\n<\/code><\/pre>\n\n<p>This is much easier to read and understand. It\u2019s amazing the difference simply splitting up large, complex bits of code can make to a codebase.\nAnother thing to note here is that you should use descriptive function names when splitting up complex functions like this. Remember, the aim is human readability. Trying to be too concise with your function names can actually make your code harder to understand. For example:<\/p>\n\n<pre><code>\n$this-&gt;get_att_inf( $post_id );\n<\/code><\/pre>\n\n<p>Is harder to understand than:<\/p>\n\n<pre><code>$this-&gt;get_attachment_s3_info( $post_id );\n<\/code><\/pre>\n\n<h2 id=\"splitting-up-complex-conditionals\">Splitting Up Complex Conditionals<\/h2>\n\n<p>Have you ever seen big conditionals that look something like:<\/p>\n\n<pre><code>&lt;?php\n\nif ( isset( $settings['wp-uploads'] ) &amp;&amp; $settings['wp-uploads'] &amp;&amp; in_array( $key, array( 'copy-to-s3', 'serve-from-s3' ) ) ) {\n    return '1';\n}\n<\/code><\/pre>\n\n<p>Long pieces of code with conditionals are hard to read and understand. A simple solution to this is to extract the conditional code into clearly named methods. For example:<\/p>\n\n<pre><code>&lt;?php\n\nif ( upload_is_valid( $settings, $key ) ) {\n    return '1';\n}\n\nfunction upload_is_valid( $settings, $key ) {\n    return isset( $settings['wp-uploads'] ) &amp;&amp; $settings['wp-uploads'] &amp;&amp; in_array( $key, array( 'copy-to-s3', 'serve-from-s3' ) );\n}\n<\/code><\/pre>\n\n<p>This makes your code far easier to understand for a future maintainer. As long as the conditional method is clearly named, it should be easy to understand what it does without inspecting the actual method code. This practice is known as declarative programming.<\/p>\n\n<h2 id=\"replacing-nested-conditionals-with-guard-clauses\">Replacing Nested Conditionals with Guard Clauses<\/h2>\n\n<p>Another way to refactor complex conditionals is to use guard clauses. Guard clauses extract all conditionals that lead to calling an exception or immediate return of a value from the method, and place it at the beginning of the method. Let\u2019s take a look at the complex function below, created without using guard clauses.<\/p>\n\n<pre><code>&lt;?php\n\nfunction get_setting( $key, $default = '' ) {\n    $settings = $this-&gt;get_settings();\n\n    \/\/ If legacy setting set, migrate settings\n    if ( isset( $settings['wp-uploads'] ) &amp;&amp; $settings['wp-uploads'] &amp;&amp; in_array( $key, array( 'copy-to-s3', 'serve-from-s3' ) ) ) {\n        return $default;\n    } else {\n        \/\/ Turn on object versioning by default\n        if ( 'object-versioning' == $key &amp;&amp; ! isset( $settings['object-versioning'] ) ) {\n            return $default;\n        } else {\n            \/\/ Default object prefix\n            if ( 'object-prefix' == $key &amp;&amp; ! isset( $settings['object-prefix'] ) ) {\n                return $this-&gt;get_default_object_prefix();\n            } else {\n                if ( 'use-yearmonth-folders' == $key &amp;&amp; ! isset( $settings['use-yearmonth-folders'] ) ) {\n                    return get_option( 'uploads_use_yearmonth_folders' );\n                } else {\n                    $value = parent::get_setting( $key, $default );\n                    return apply_filters( 'as3cf_setting_' . $key, $value );\n                }\n            }\n        }\n    }\n\n    return $default;\n}\n<\/code><\/pre>\n\n<p>Here you can see how you could quickly end up in \u201cconditional hell\u201d if the method got any more complex. However, when we refactor to use guard clauses, it looks like this:<\/p>\n\n<pre><code>&lt;?php\n\nfunction get_setting( $key, $default = '' ) {\n    $settings = $this-&gt;get_settings();\n\n    \/\/ If legacy setting set, migrate settings\n    if ( isset( $settings['wp-uploads'] ) &amp;&amp; $settings['wp-uploads'] &amp;&amp; in_array( $key, array( 'copy-to-s3', 'serve-from-s3' ) ) ) {\n        return $default;\n    }\n\n    \/\/ Turn on object versioning by default\n    if ( 'object-versioning' == $key &amp;&amp; ! isset( $settings['object-versioning'] ) ) {\n        return $default;\n    }\n\n    \/\/ Default object prefix\n    if ( 'object-prefix' == $key &amp;&amp; ! isset( $settings['object-prefix'] ) ) {\n        return $this-&gt;get_default_object_prefix();\n    }\n\n    \/\/ Default use year and month folders\n    if ( 'use-yearmonth-folders' == $key &amp;&amp; ! isset( $settings['use-yearmonth-folders'] ) ) {\n        return get_option( 'uploads_use_yearmonth_folders' );\n    }\n\n    $value = parent::get_setting( $key, $default );\n\n    return apply_filters( 'as3cf_setting_' . $key, $value );\n}\n<\/code><\/pre>\n\n<p>Now even if the method gets more complex, it\u2019s not going to be a maintenance headache down the road.<\/p>\n\n<h2 id=\"refactoring-loops-and-conditionals-using-functional-methods\">Refactoring Loops and Conditionals Using Functional Methods<\/h2>\n\n<p>This is a slightly more advanced type of refactoring that is used more heavily in functional programming languages and libraries such as JavaScript, but can also be applied to PHP. Functions like <code>map<\/code> and <code>reduce<\/code> can dramatically improve the readability of your code.<\/p>\n\n<p>The examples below were inspired by <a href=\"http:\/\/adamwathan.me\/2015\/01\/01\/refactoring-loops-and-conditionals\/\">Adam Wathan\u2019s great screencast<\/a> on the subject and is based on using Laravel Collections. However, the example has been adapted to work with standard PHP functions. Speaking of Adam, his book \u201c<a href=\"https:\/\/www.goodreads.com\/book\/show\/30238532-refactoring-to-collections\">Refactoring to Collections<\/a>\u201d is a great guide to writing clean and maintainable PHP.<\/p>\n\n<p>Let\u2019s look at two common scenarios and see how they can be improved using functional methods. The example below fetches a bunch of <code>$events<\/code> from an API and calculates a score based on the event type:<\/p>\n\n<pre><code>&lt;?php\n\n$events = file_get_contents( 'https:\/\/someapi.com\/events' );\n\n$types = array();\nforeach ( $events as $event ) {\n    $types[] = $event-&gt;type;\n}\n\n$score = 0;\n\nforeach ( $types as $type ) {\n    switch ( $type ) {\n        case 'type1':\n            $score += 2;\n            break;\n        case 'type2':\n            $score += 5;\n            break;\n        case 'type3':\n            $score += 10;\n            break;\n        default:\n            $score += 1;\n            break;\n    }\n}\n<\/code><\/pre>\n\n<p>The first thing we can improve is replacing the <code>foreach<\/code> loop with a <code>map<\/code> function. A map function can be used when you want to create a new array from an existing array. In our example we\u2019re creating a <code>$types<\/code> array from the <code>$events<\/code> array. PHP has an <a href=\"http:\/\/php.net\/manual\/en\/function.array-map.php\">array_map<\/a> function that will let us write the first <code>foreach<\/code> in the above code like this:<\/p>\n\n<pre><code>&lt;?php\n\n$types = array_map( function( $event ) {\n    return $event-&gt;type;\n}, $events );\n<\/code><\/pre>\n\n<p>The second thing we can do is break down the big <code>switch<\/code> statement so it\u2019s a bit easier to process.<\/p>\n\n<pre><code>&lt;?php\n\n$scores = array(\n    'type1' =&gt; 2,\n    'type2' =&gt; 5,\n    'type3' =&gt; 10,\n);\n\n$score = 0;\n\nforeach ( $types as $type ) {\n    $score += isset( $scores[$type] ) ? $scores[$type] : 1;\n}\n\n<\/code><\/pre>\n\n<p>But we can actually go one step further here and use PHP\u2019s <a href=\"http:\/\/php.net\/manual\/en\/function.array-reduce.php\">array_reduce<\/a> function to calculate the <code>$score<\/code> in a single function. A reduce function takes an array of values and reduces them to a single value. We\u2019re going to do that here to calculate our <code>$score<\/code>.<\/p>\n\n<pre><code>&lt;?php\n\n$scores = array(\n    'type1' =&gt; 2,\n    'type2' =&gt; 5,\n    'type3' =&gt; 10,\n);\n\n$score = array_reduce( $types, function( $result, $type ) use ( $scores ) {\n    return $result += isset( $scores[$type] ) ? $scores[$type] : 1;\n} );\n<\/code><\/pre>\n\n<p>Putting it all together we now have:<\/p>\n\n<pre><code>&lt;?php\n\n$events = file_get_contents( 'https:\/\/someapi.com\/events' );\n\n$types = array_map( function( $event ) {\n    return $event-&gt;type;\n}, $events );\n\n$scores = array(\n    'type1' =&gt; 2,\n    'type2' =&gt; 5,\n    'type3' =&gt; 10,\n);\n\n$score = array_reduce( $types, function( $result, $type ) use ( $scores ) {\n    return $result += isset( $scores[$type] ) ? $scores[$type] : 1;\n} );\n<\/code><\/pre>\n\n<p>Much better. No loops or conditionals in sight. You could imagine how, if more complexity was required to find <code>$types<\/code> or calculate the <code>$score<\/code> down the line, it would be easy to refactor the <code>map<\/code> and <code>reduce<\/code> function calls into separate methods. This is now possible because we&#8217;ve already reduced the complexity down to a function.<\/p>\n\n<h2 id=\"further-reading\">Further Reading<\/h2>\n\n<p>This article just scrapes the surface of refactoring, concentrating on the human readability aspects. For a deeper dive, check out <a href=\"https:\/\/phptherightway.com\/#refactoring\">PHP The Right Way<\/a> or <a href=\"https:\/\/sourcemaking.com\/refactoring\">SourceMaking Refactoring guide<\/a>.<\/p>\n\n<p>How highly do you value the human readability aspects of your code?  Let us know in the comments.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Refactoring code is when you restructure existing code without changing its external behavior. Basically your aim is to make \u201cbad\u201d code better without changing the underlying functionality, and one of&hellip; <a href=\"https:\/\/deliciousbrains.com\/refactoring-php-code-better-readability\/\">Read&nbsp;more<\/a><\/p>","protected":false},"author":4535,"featured_media":16338,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[484,476],"tags":[195,162,104,41],"class_list":["post-16214","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-wp-offload-media-code","category-wp-offload-media","tag-refactoring","tag-php","tag-code","tag-development"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Examples of Refactoring PHP Code for Better Readability<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/deliciousbrains.com\/refactoring-php-code-better-readability\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Examples of Refactoring PHP Code for Better Readability\" \/>\n<meta property=\"og:description\" content=\"Refactoring code is when you restructure existing code without changing its external behavior. Basically your aim is to make \u201cbad\u201d code better without changing the underlying functionality, and one of&hellip; Read&nbsp;more\" \/>\n<meta property=\"og:url\" content=\"https:\/\/deliciousbrains.com\/refactoring-php-code-better-readability\/\" \/>\n<meta property=\"og:site_name\" content=\"Delicious Brains\" \/>\n<meta property=\"article:published_time\" content=\"2023-09-15T16:00:59+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-04-10T13:58:17+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/cdn.deliciousbrains.com\/content\/uploads\/2016\/04\/15162141\/db-refactoringphpcode.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2500\" \/>\n\t<meta property=\"og:image:height\" content=\"1214\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Gilbert Pellegrom\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@gilbitron\" \/>\n<meta name=\"twitter:site\" content=\"@dliciousbrains\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Gilbert Pellegrom\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/deliciousbrains.com\\\/refactoring-php-code-better-readability\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/deliciousbrains.com\\\/refactoring-php-code-better-readability\\\/\"},\"author\":{\"name\":\"Gilbert Pellegrom\",\"@id\":\"https:\\\/\\\/deliciousbrains.com\\\/#\\\/schema\\\/person\\\/b0e45f66e8e428fc0f512d1cf0095f8b\"},\"headline\":\"Examples of Refactoring PHP Code for Better&nbsp;Readability\",\"datePublished\":\"2023-09-15T16:00:59+00:00\",\"dateModified\":\"2024-04-10T13:58:17+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/deliciousbrains.com\\\/refactoring-php-code-better-readability\\\/\"},\"wordCount\":1252,\"commentCount\":9,\"image\":{\"@id\":\"https:\\\/\\\/deliciousbrains.com\\\/refactoring-php-code-better-readability\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/cdn.deliciousbrains.com\\\/content\\\/uploads\\\/2016\\\/04\\\/15162141\\\/db-refactoringphpcode.jpg\",\"keywords\":[\"Refactoring\",\"PHP\",\"Code\",\"Development\"],\"articleSection\":[\"Code\",\"WP Offload Media\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/deliciousbrains.com\\\/refactoring-php-code-better-readability\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/deliciousbrains.com\\\/refactoring-php-code-better-readability\\\/\",\"url\":\"https:\\\/\\\/deliciousbrains.com\\\/refactoring-php-code-better-readability\\\/\",\"name\":\"Examples of Refactoring PHP Code for Better Readability\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/deliciousbrains.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/deliciousbrains.com\\\/refactoring-php-code-better-readability\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/deliciousbrains.com\\\/refactoring-php-code-better-readability\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/cdn.deliciousbrains.com\\\/content\\\/uploads\\\/2016\\\/04\\\/15162141\\\/db-refactoringphpcode.jpg\",\"datePublished\":\"2023-09-15T16:00:59+00:00\",\"dateModified\":\"2024-04-10T13:58:17+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/deliciousbrains.com\\\/#\\\/schema\\\/person\\\/b0e45f66e8e428fc0f512d1cf0095f8b\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/deliciousbrains.com\\\/refactoring-php-code-better-readability\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/deliciousbrains.com\\\/refactoring-php-code-better-readability\\\/#primaryimage\",\"url\":\"https:\\\/\\\/cdn.deliciousbrains.com\\\/content\\\/uploads\\\/2016\\\/04\\\/15162141\\\/db-refactoringphpcode.jpg\",\"contentUrl\":\"https:\\\/\\\/cdn.deliciousbrains.com\\\/content\\\/uploads\\\/2016\\\/04\\\/15162141\\\/db-refactoringphpcode.jpg\",\"width\":2500,\"height\":1214},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/deliciousbrains.com\\\/#website\",\"url\":\"https:\\\/\\\/deliciousbrains.com\\\/\",\"name\":\"Delicious Brains\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/deliciousbrains.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/deliciousbrains.com\\\/#\\\/schema\\\/person\\\/b0e45f66e8e428fc0f512d1cf0095f8b\",\"name\":\"Gilbert Pellegrom\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/assets.deliciousbrains.com\\\/avatar\\\/4f8eb902c2592db06ac93be333dafe9107f16cc8c86608143899f28707bda974?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/assets.deliciousbrains.com\\\/avatar\\\/4f8eb902c2592db06ac93be333dafe9107f16cc8c86608143899f28707bda974?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/assets.deliciousbrains.com\\\/avatar\\\/4f8eb902c2592db06ac93be333dafe9107f16cc8c86608143899f28707bda974?s=96&d=mm&r=g\",\"caption\":\"Gilbert Pellegrom\"},\"description\":\"Gilbert loves to build software. From jQuery scripts to WordPress plugins to full blown SaaS apps, Gilbert has been creating elegant software his whole career. Probably most famous for creating the Nivo Slider.\",\"sameAs\":[\"https:\\\/\\\/gilbitron.me\",\"https:\\\/\\\/x.com\\\/gilbitron\"],\"url\":\"https:\\\/\\\/deliciousbrains.com\\\/author\\\/gilbert-pellegrom\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Examples of Refactoring PHP Code for Better Readability","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/deliciousbrains.com\/refactoring-php-code-better-readability\/","og_locale":"en_US","og_type":"article","og_title":"Examples of Refactoring PHP Code for Better Readability","og_description":"Refactoring code is when you restructure existing code without changing its external behavior. Basically your aim is to make \u201cbad\u201d code better without changing the underlying functionality, and one of&hellip; Read&nbsp;more","og_url":"https:\/\/deliciousbrains.com\/refactoring-php-code-better-readability\/","og_site_name":"Delicious Brains","article_published_time":"2023-09-15T16:00:59+00:00","article_modified_time":"2024-04-10T13:58:17+00:00","og_image":[{"width":2500,"height":1214,"url":"https:\/\/cdn.deliciousbrains.com\/content\/uploads\/2016\/04\/15162141\/db-refactoringphpcode.jpg","type":"image\/jpeg"}],"author":"Gilbert Pellegrom","twitter_card":"summary_large_image","twitter_creator":"@gilbitron","twitter_site":"@dliciousbrains","twitter_misc":{"Written by":"Gilbert Pellegrom","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/deliciousbrains.com\/refactoring-php-code-better-readability\/#article","isPartOf":{"@id":"https:\/\/deliciousbrains.com\/refactoring-php-code-better-readability\/"},"author":{"name":"Gilbert Pellegrom","@id":"https:\/\/deliciousbrains.com\/#\/schema\/person\/b0e45f66e8e428fc0f512d1cf0095f8b"},"headline":"Examples of Refactoring PHP Code for Better&nbsp;Readability","datePublished":"2023-09-15T16:00:59+00:00","dateModified":"2024-04-10T13:58:17+00:00","mainEntityOfPage":{"@id":"https:\/\/deliciousbrains.com\/refactoring-php-code-better-readability\/"},"wordCount":1252,"commentCount":9,"image":{"@id":"https:\/\/deliciousbrains.com\/refactoring-php-code-better-readability\/#primaryimage"},"thumbnailUrl":"https:\/\/cdn.deliciousbrains.com\/content\/uploads\/2016\/04\/15162141\/db-refactoringphpcode.jpg","keywords":["Refactoring","PHP","Code","Development"],"articleSection":["Code","WP Offload Media"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/deliciousbrains.com\/refactoring-php-code-better-readability\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/deliciousbrains.com\/refactoring-php-code-better-readability\/","url":"https:\/\/deliciousbrains.com\/refactoring-php-code-better-readability\/","name":"Examples of Refactoring PHP Code for Better Readability","isPartOf":{"@id":"https:\/\/deliciousbrains.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/deliciousbrains.com\/refactoring-php-code-better-readability\/#primaryimage"},"image":{"@id":"https:\/\/deliciousbrains.com\/refactoring-php-code-better-readability\/#primaryimage"},"thumbnailUrl":"https:\/\/cdn.deliciousbrains.com\/content\/uploads\/2016\/04\/15162141\/db-refactoringphpcode.jpg","datePublished":"2023-09-15T16:00:59+00:00","dateModified":"2024-04-10T13:58:17+00:00","author":{"@id":"https:\/\/deliciousbrains.com\/#\/schema\/person\/b0e45f66e8e428fc0f512d1cf0095f8b"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/deliciousbrains.com\/refactoring-php-code-better-readability\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/deliciousbrains.com\/refactoring-php-code-better-readability\/#primaryimage","url":"https:\/\/cdn.deliciousbrains.com\/content\/uploads\/2016\/04\/15162141\/db-refactoringphpcode.jpg","contentUrl":"https:\/\/cdn.deliciousbrains.com\/content\/uploads\/2016\/04\/15162141\/db-refactoringphpcode.jpg","width":2500,"height":1214},{"@type":"WebSite","@id":"https:\/\/deliciousbrains.com\/#website","url":"https:\/\/deliciousbrains.com\/","name":"Delicious Brains","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/deliciousbrains.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/deliciousbrains.com\/#\/schema\/person\/b0e45f66e8e428fc0f512d1cf0095f8b","name":"Gilbert Pellegrom","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/assets.deliciousbrains.com\/avatar\/4f8eb902c2592db06ac93be333dafe9107f16cc8c86608143899f28707bda974?s=96&d=mm&r=g","url":"https:\/\/assets.deliciousbrains.com\/avatar\/4f8eb902c2592db06ac93be333dafe9107f16cc8c86608143899f28707bda974?s=96&d=mm&r=g","contentUrl":"https:\/\/assets.deliciousbrains.com\/avatar\/4f8eb902c2592db06ac93be333dafe9107f16cc8c86608143899f28707bda974?s=96&d=mm&r=g","caption":"Gilbert Pellegrom"},"description":"Gilbert loves to build software. From jQuery scripts to WordPress plugins to full blown SaaS apps, Gilbert has been creating elegant software his whole career. Probably most famous for creating the Nivo Slider.","sameAs":["https:\/\/gilbitron.me","https:\/\/x.com\/gilbitron"],"url":"https:\/\/deliciousbrains.com\/author\/gilbert-pellegrom\/"}]}},"_links":{"self":[{"href":"https:\/\/deliciousbrains.com\/wp-json\/wp\/v2\/posts\/16214","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/deliciousbrains.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/deliciousbrains.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/deliciousbrains.com\/wp-json\/wp\/v2\/users\/4535"}],"replies":[{"embeddable":true,"href":"https:\/\/deliciousbrains.com\/wp-json\/wp\/v2\/comments?post=16214"}],"version-history":[{"count":0,"href":"https:\/\/deliciousbrains.com\/wp-json\/wp\/v2\/posts\/16214\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/deliciousbrains.com\/wp-json\/wp\/v2\/media\/16338"}],"wp:attachment":[{"href":"https:\/\/deliciousbrains.com\/wp-json\/wp\/v2\/media?parent=16214"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/deliciousbrains.com\/wp-json\/wp\/v2\/categories?post=16214"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/deliciousbrains.com\/wp-json\/wp\/v2\/tags?post=16214"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}