Backward Compatibility: Practice

Welcome back! Today, we'll master what we learned about backward compatibility in practice. Prepare to apply all the knowledge to practical tasks, but first, let's look at two examples and analyze them.

Task 1: Enhancing a Complex Data Processing Function with Optional Parameters and Default Values

Let's say that initially, we have a complex data processing class designed to operate on an array of associative arrays, applying a transformation that converts all string values within the array to uppercase. Here's the initial version using PHP:

<?php
class DataProcessor
{
    public function processData(array $items)
    {
        $processedItems = [];
        foreach ($items as $item) {
            $processedItem = [];
            foreach ($item as $key => $value) {
                if (is_string($value)) {
                    $processedItem[$key] = strtoupper($value);
                } else {
                    $processedItem[$key] = $value;
                }
            }
            $processedItems[] = $processedItem;
        }
        
        for ($i = 0; $i < min(3, count($processedItems)); $i++) {
            echo "Processed Item: ";
            print_r($processedItems[$i]);
        }
    }
}

We intend to expand this functionality, adding capabilities to filter the items based on a condition and allowing for custom transformations. The aim is to retain backward compatibility while introducing these enhancements. Here's the updated approach using optional parameters and closures:

<?php
class DataProcessor
{
    public function processData(array $items, callable $condition = null, callable $transform = null)
    {
        if ($condition === null) {
            $condition = function ($item) {
                return true;
            };
        }
        
        $processedItems = [];
        foreach ($items as $item) {
            if ($condition($item)) {
                $processedItem = [];
                
                if ($transform !== null) {
                    $processedItem = $transform($item);
                } else {
                    // Default transformation: Convert string values to uppercase
                    foreach ($item as $key => $value) {
                        $processedItem[$key] = is_string($value) ? strtoupper($value) : $value;
                    }
                }
                
                $processedItems[] = $processedItem;
            }
        }
        
        for ($i = 0; $i < min(3, count($processedItems)); $i++) {
            echo "Processed Item: ";
            print_r($processedItems[$i]);
        }
    }
}

// Usage examples:
$data = [
    ["name" => "apple", "quantity" => 10],
    ["name" => "orange", "quantity" => 5]
];

$processor = new DataProcessor();

// Default behavior - convert string values to uppercase
$processor->processData($data);

// Custom filter - select items with a quantity greater than 5
$processor->processData($data, function ($item) {
    return $item['quantity'] > 5;
});

// Custom transformation - convert names to uppercase and multiply the quantity by 2
$processor->processData($data, null, function ($item) {
    return [
        'name' => strtoupper($item['name']),
        'quantity' => $item['quantity'] * 2
    ];
});

In this evolved version, we've used optional parameters callable $condition and callable $transform for custom filtering and transformation of items. The default behavior processes all items, converting string values to uppercase, thus maintaining original functionality for existing code paths.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal