Web Development Articles

What is the PHP Spread Operator (...)

0 👍
👎 0
 PHP

Spread Operator (...)

The PHP Spread Operator (...) is a powerful feature introduced in PHP 5.6 that allows you to "unpack" or "spread" elements from arrays and traversable objects. It's also known as the splat operator or unpacking operator.

The spread operator is particularly useful in modern PHP development for creating more expressive and efficient code when working with arrays and variable function arguments.

Key Benefits of the PHP Spread Operator

  1. Cleaner syntax for array merging and function calls

  2. Better performance in some cases compared to array_merge()

  3. More readable code when dealing with multiple arrays

  4. Flexible for both array operations and function arguments


Here are a few common use cases for the operator:

Unpack and Merge Multiple Arrays

Here are a couple of examples for unpacking and merging arrays.  

 

 $array1 = [1, 2, 3];

 $array2 = [4, 5, 6];

 $array3 = [7, 8, 9];

 

 $merged = [...$array1, ...$array2, ...$array3];

 

 // Array (

 //  [0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 5

 //  [5] => 6 [6] => 7 [7] => 8 [8] => 9

 // )

 

 

 $original = ['b', 'c', 'd'];

 $newArray = ['a', ...$original, 'e'];

 // Array (

 //   [0] => a [1] => b [2] => c [3] => d [4] => e

 // )

 

 

Function Arguments

 

 // FUNCTION ARGUMENTS

 function addNumbers($a, $b, $c) {

    return $a + $b + $c;

 }

 

 $numbers = [2, 4, 6];

 $result = addNumbers(...$numbers);

 echo $result; // Output: 12

 

 

 function sum(...$numbers) {

    return array_sum($numbers);

 }

 

 $values = [1, 2, 3, 4, 5];

 echo sum(...$values); // Output: 15

 

Combining With Regular Elements

 

 // Combining with Regular Elements

 $first = [1, 2];

 $last = [5, 6];

 $combined = [...$first, 3, 4, ...$last];

 print_r($combined);

 // Output: Array ([0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 5 [5] => 6)

 

 

Usage With Associative Arrays

Notice that array keys are also considered making it perfect for merging associative arrays as well.  

 //With Associative Arrays

 $config1 = ['host' => 'localhost', 'port' => 3306];

 $config2 = ['username' => 'root', 'password' => 'secret'];

 

 $finalConfig = [...$config1, ...$config2];

 print_r($finalConfig);

// Output: Array ([host] => localhost [port] => 3306 [username] => root [password] => secret)

 

 

String To Array Conversion

 

 // String To Array Conversion

 $string = "hello";

 $chars = [...$string];

 print_r($chars);

 // Output: Array ([0] => h [1] => e [2] => l [3] => l [4] => o)

 

 

Practical Example of Merging 2 Configuration Arrays

Remember that when merging 2 associative arrays using the spread operator and brackets syntax, the second array in the will overwrite values with matching keys.  Take a look at the ‘debug’ key below:

 

 // Configuration Merging

 $defaultConfig = [

    'debug' => false,

    'cache' => true,

    'timeout' => 30

 ];

 

 $userConfig = [

    'debug' => true,

    'database' => 'mysql'

 ];

 

 $finalConfig = [...$defaultConfig, ...$userConfig];

 print_r($finalConfig);

 // Output: Array ([debug] => true [cache] => true [timeout] => 30 [database] => mysql)

 




Using the Javascript Switch Statement

1 👍
👎 0
 NodeJS
 ReactJS
 Javascript

Overview of the Switch Statement


  The switch statement is a control structure available in almost every programming and scripting language.  It allows the developer to execute different blocks of code based on the value of an expression.  It is often used as a cleaner alternative to multiple if-else statements.  You may be asking yourself why use the switch statement since we already have if-else.  


   There are differences though.  And depending on the task-at-hand, the switch statement can be a better alternative than
if-else.  

Structure:

 

 switch (expression) {

    case value1:

        // execute this code block only

        break;

    case value2:

        // execute this code block only

        break;

    default:

        // execute if no cases match

 }


   A
switch statement evaluates an expression and executes the code block for the first case that matches its value.

   The break keyword is crucial. When encountered, it exits the entire switch statement immediately. Without it, execution will "fall through" and run the code in the subsequent case, even if the value doesn't match.  If no matching case is found, the optional default block is executed.

Example:

 

 let day = 'Monday';

 let output = '';

 switch (day) {

    case 'Monday':

        output = `Day is Monday`;

    case 'Tuesday':

        output = `Day is Tuesday`;

        break;

    case 'Wednesday':

        output = `Day is Wednesday`;

        break;

    case 'Thursday':

        output = `Day is Thursday`;

        break;

    case 'Friday':

        output = `Day is Friday`;

        break;

    case 'Saturday':

        output = `Day is Saturday`;

        break;

    case 'Sunday':

        output = `Day is Sunday`;

        break;

    default:

        output = `No day specified`;

 }

 

 // Output if day == 'Monday' OR day == 'Tuesday':

 // Day is Tuesday

 

 // Output if day == 'Saturday':

 // Day is Saturday

 

 // Output if day == 'Nothing'

 // No day specified

 


   This example demonstrates a crucial concept in JavaScript's
switch statement: fallthrough.  When day is 'Monday', the output will indeed be "Day is Tuesday".  Here’s why: The switch statement finds a match on case 'Monday' and begins executing the code on the next line, setting output = 'Day is Monday'.

  Because there is no break keyword at the end of the 'Monday' case, the logic "falls through" and continues to execute the very next line of code, which is the start of the 'Tuesday' case.  It then executes output = 'Day is Tuesday', overwriting the previous value.  Finally, the break keyword at the end of the 'Tuesday' case is encountered, which halts the execution of the switch block entirely.

   The break statement is not optional for most use cases. It is essential for exiting the switch block once a specific case's code has finished running. Without it, execution will continue into the next case, whether it matches or not.


   The
default case is only executed if no other case values match the expression. It will not be executed simply because of a fallthrough from a matched case (unless that fallthrough leads all the way to it).

PHP Null Coalescing Operator ??

0 👍
👎 0
 LAMP
The null coalescing operator ?? is used similar to the elvis operator ?:  In the example below the value of $var3 will only be the value of $var2 if $var1 is null.  With no value will $var3 be the value of $var1. 
 
Example 1:

$var1 = null;  // it's null
$var2 = 15;
$var3 = $var1 ?? $var2; // the value is 15

OR
$var1;  // it's undfefined
$var2 = 15;
$var3 = $var1 ?? $var2; // the value is 15

In Example 1 above the value of $var3 will be the value of $var2.  This is because value of $var1 is null or undefined.  If $var1 is any value besides null, the value of $var3 would be the value of $var1.  That case is displayed in Example 2 below.

In Example 2:

$var1 = 3;
$var2 = 15;
$var3 = $var1 ?? $var2;   // the value is 3

PHP Null-Safe(Null-Conditional) Operator (?->)

0 👍
👎 0
 Laravel
 PHP

Null-Safe(Null-Conditional) Operator (?->)

The null-safe operator (?->), also known as the null-conditional operator, is a feature in several programming languages that allows you to safely access members of an object without explicitly checking for null references. If the object is null, the expression returns null instead of throwing a NullPointerException.

 

Basic Property Access

 

 class User {

   public ?Profile $profile = null;

 }

 

 class Profile {

   public string $name = "John Doe";

   public ?Address $address = null;

 

   public function getName(): string {

       return $this->name;

   }

 }

 

 class Address {

   public string $street = "123 Main St";

 }

 

 $user = new User();

 

 // Safe property access

 $name = $user?->profile?->name; // Returns null instead of error

 var_dump($name); // NULL

 

 // With actual data

 $user->profile = new Profile();

 $name = $user?->profile?->name;

 var_dump($name); // string(8) "John Doe"

 

Method Calls


$user = new User();

 

 // Safe method call

 $result = $user?->profile?->getName(); // Returns null

 var_dump($result); // NULL

 

 $user->profile = new Profile();

 $result = $user?->profile?->getName();

 var_dump($result); // string(8) "John Doe"

 

 

Array Access with Null-Safe

 

 class DataContainer {

    public ?array $items = null;

   

    public function getItems(): ?array {

        return $this->items;

    }

 }

 

 $container = new DataContainer();

 

 // Safe array access

 $firstItem = $container?->items[0] ?? 'default';

 var_dump($firstItem); // string(7) "default"

 

 $container->items = ['apple', 'banana'];

 $firstItem = $container?->items[0] ?? 'default';

 var_dump($firstItem); // string(5) "apple"

 

 

Chaining Multiple Levels

 

 $user = new User();

 $user->profile = new Profile();

 $user->profile->address = new Address();

 

 // Deep chaining

 $street = $user?->profile?->address?->street;

 var_dump($street); // string(11) "123 Main St"

 

 // With null in chain

 $user->profile->address = null;

 $street = $user?->profile?->address?->street;

 var_dump($street); // NULL

 

 

Used with Null-Coalescing Operator

 

 $user = null;

 

 // Null-safe + null coalescing

 $userName = $user?->profile?->name ?? 'Guest';

 var_dump($userName); // string(5) "Guest"

 

 $user = new User();

 $userName = $user?->profile?->name ?? 'Guest';

 var_dump($userName); // string(5) "Guest"

 

 $user->profile = new Profile();

 $userName = $user?->profile?->name ?? 'Guest';

 var_dump($userName); // string(8) "John Doe"

 



Used with Ternary Operator

 

 $user = null;

 

 $displayName = $user?->profile?->name ?: 'Anonymous User';

 var_dump($displayName); // string(15) "Anonymous User"

 



Key Benefits

1. Reduces Boilerplate: Eliminates repetitive null checks
2. Prevents NullPointerExceptions: Safe access to nested properties
3. Cleaner Code: More readable and concise syntax
4. Short-Circuiting: Stops evaluation when null is encountered
5. Method Safety: Safe method calls on potentially null objects

Limitations

1. Read-Only: Cannot be used for assignment

2. Context-Specific: Only works in expressions, not statements

3. Language Support: Syntax varies between languages

4. Debugging: Can make null-related bugs harder to trace

The null-safe operator is particularly useful in scenarios with deep object graphs, API responses, configuration objects, and any situation where multiple nested objects might be null.

 

A Quick HowTo of PHP Operators

0 👍
👎 0
 LAMP

Math Operators

Addition:
Caculate the sum of two numbers using the + operator.

$sum = 1 + 3;
The value of $sum is 4.

Subtraction:
Caculate the difference of two numbers using the - operator.

$diff = 3 - 2;
The value of $diff is 1.

Division:
Calculate the quotient of two numbers using the / operator.

$quotient = 4 / 2;
The value of $quotient is 2.

Multiplication:
Calculate the product using the * operator.

$product = 4 * 5;
The value of $product is 20.

Modulo:
Gives the remainder after dividing two numbers the % operator.

$remainder = 10 % 3;
The value of $remainder is 1.

JavaScript Promises and Asynchronous Handling Explained

0 👍
👎 0
 Javascript

Have you ever made an HTTP API request in JavaScript, only to find the data you need is mysteriously unavailable? You're confident the server-side API works, as you've tested it repeatedly. The issue often lies in JavaScript's asynchronous nature.

JavaScript doesn't pause execution to wait for slow operations, like API calls, to complete. Instead, it triggers the request and immediately moves on to the next line of code. By the time your script tries to use the response data, the request may not have finished.

This is where the Promise object becomes essential. A Promise represents the eventual completion (or failure) of an asynchronous operation and its resulting value. Let's explore how to use them effectively.

 

First let’s take a look at the most commonly used methods available on a JavaScript Promise object (Promise.then()):

 

1. Basic Promise Handling with .then()

 

The .then() method is the primary way to interact with a Promise. You can pass it two functions: one to handle a successful resolution and another to handle a rejection.

 

 

 let name = "Mary";

 const promise = new Promise((resolve, reject) => {

    name == "Mary" ? resolve(name) : reject(name);

 });

 

 // promise.then(onFulfilled, onRejected)

 promise.then(

    x => console.log(`Name resolved: ${x}`), // Called if resolved

    x => console.log(`Name rejected: ${x}`// Called if rejected

 );

 // Expected output: "Name resolved: Mary"

 

 

 

2. Chaining Multiple .then() Methods

 

Promises are powerful because they can be chained, allowing you to define a sequence of asynchronous steps. Each .then() in the chain receives the result from the previous one.

 

 

 let name = "Mary";

 

 // Function passed to the Promise constructor

 const analyzeName = (resolve, reject) => {

    name == "Mary" ? resolve(name) : reject(name);

 };

 

 // Handler for a resolved promise

 const nameResolved = (x) => {

    console.log(`Name resolved: ${x}`);

    return x; // Pass the value to the next .then()

 };

 

 // Handler for a rejected promise

 const nameRejected = (x) => {

    console.log(`Name rejected: ${x}`);

    return x; // Even on rejection, we can pass the value down the chain

 };

 

 // Subsequent steps in the process

 const step2 = (x) => {

    console.log(`Step 2: Processing ${x}`);

    return x;

 };

 

 const step3 = (x) => {

    console.log(`Final Step: ${x}`);

    return x;

 };

 

 const namePromise = new Promise(analyzeName);

 

 namePromise

 .then(nameResolved, nameRejected) // Handles the initial result

 .then(step2// Receives the value from nameResolved/nameRejected

 .then(step3); // Receives the value from step2

 

 // Console Output:

 // Name resolved: Mary

 // Step 2: Processing Mary

 // Final Step: Mary

 


By using Promises and its
.then() method, you gain precise control over the flow of your asynchronous code. This ensures that each step waits for the previous one to complete before executing, which is the fundamental solution to the "missing data" problem in async operations like API calls. For modern, cleaner syntax, consider using async/await, which is built on top of Promises.


Here is a comprehensive example that builds on the previous explanation by adding
.catch() and .finally() methods, which are crucial for robust promise handling.

While .then() handles successful outcomes, a complete promise chain needs ways to handle errors and cleanup operations. This is where .catch() and .finally() come in.

- catch() - Handles any rejection that occurs in the chain

- finally() - Executes regardless of success or failure, perfect for cleanup


Below I’ve included a real-world example with HTTP request and a more practical example of its use with proper error handling.



Practical Example: User Data Fetch with Complete Error Handling


 

 // Simulate fetching user data from an API

 const fetchUserData = (userId) => {

    return new Promise((resolve, reject) => {

        console.log(`Fetching data for user ${userId}...`);

      

        // Simulate API call delay

        setTimeout(() => {

            const users = {

                1: { id: 1, name: "Alice", role: "admin" },

                2: { id: 2, name: "Bob", role: "user" }

            };

          

            const user = users[userId];

           

            if (user) {

                resolve(user); // Success case

            } else {

                reject(new Error(`User ${userId} not found`)); // Error case

            }

        }, 1000);

    });

 };

 

 // Processing functions for our chain

 const validateUserRole = (user) => {

    console.log(`Validating role for: ${user.name}`);

    if (user.role !== 'admin') {

        throw new Error('Insufficient permissions'); // This will trigger .catch()

    }

    return user; // Pass to next .then()

 };

 

 const logAccess = (user) => {

    console.log(`Access granted to ${user.name} (${user.role})`);

    return user;

 };

 

 // Example 1: Successful chain

 console.log('=== SUCCESSFUL REQUEST ===');

 fetchUserData(1) // Returns Alice (admin)

 .then(validateUserRole)

 .then(logAccess)

 .then(user => {

     console.log(`Final success: ${user.name} is logged in`);

     return user;

 })

 .catch(error => {

     console.error('Error:', error.message);

     return { error: true, message: error.message }; // Recover from error

 })
.finally(() => {

     console.log('Request completed - cleaning up resources\n');

 });

 

 // After 1 second, this will output:

 // Fetching data for user 1...

 // Validating role for: Alice

 // Access granted to Alice (admin)

 // Final success: Alice is logged in

 // Request completed - cleaning up resources

 

 

Real-Word HTTP Request Example

 

 // Real-world example with fetch API

 const loadUserProfile = (userId) => {

    console.log(`Starting profile load for user ${userId}`);

   

    fetch(`/api/users/${userId}`)

    .then(response => {

         if (!response.ok) {

            throw new Error(`HTTP error! status: ${response.status}`);

         }

         return response.json(); // Parse JSON response

     })

     .then(userData => {

         console.log('User data received:', userData);

          // Continue with data process in .then()

          return processUserData(userData);

     })

     .then(processedData => {

          updateUI(processedData);

     })

     .catch(error => {

          console.error('Failed to load profile:', error);

          showErrorMessage('Failed to load user profile');

     })

     .finally(() => {

          hideLoadingSpinner(); // Always hide spinner, success or failure

          console.log('Profile load operation completed');

     });

 };

 

 // Mock functions for the example

 const processUserData = (data) => {

    console.log('Processing user data...');

    return { ...data, processed: true };

 };

 

 const updateUI = (data) => {

    console.log('Updating UI with:', data);

 };

 

 const showErrorMessage = (message) => {

    console.log('Showing error:', message);

 };

 

 const hideLoadingSpinner = () => {

    console.log('Loading spinner hidden');

 };

 

 // Simulate calling the function

 // loadUserProfile(123);

 

 

As you can see from the last 2 examples, this pattern ensures your asynchronous code is robust, maintainable, and properly handles both success and failure scenarios.


Below is a comprehensive list of the static methods and instance methods available on a Promise:

 

Static Methods (Called on Promise class)


Promise.all()

- Returns a single Promise that resolves when all promises in the iterable have resolved

- Rejects immediately if any promise in the iterable rejects

- Results are in the same order as input promises


Promise.allSettled()

- Returns a single Promise that resolves when all promises in the iterable have settled (either fulfilled or rejected)

- Never rejects - always resolves with an array of outcome objects showing each promise's status and value/reason


Promise.any()

- Returns a single Promise that resolves when any promise in the iterable fulfills

- Only rejects if all promises are rejected (with an AggregateError)

 

Promise.race()

- Returns a single Promise that settles based on the first promise in the iterable to settle (whether fulfilled or rejected)

- Adopts the state and value/reason of the first settling promise

 

Promise.resolve()

  • Returns a Promise object that is resolved with the given value

  • Creates an immediately fulfilled promise

Promise.reject()

- Returns a Promise object that is rejected with the given reason

- Creates an immediately rejected promise

 

Instance Methods (Called on Promise instances)


.then()

- Attaches callbacks for when the promise is fulfilled or rejected

- Returns a new promise allowing for method chaining

- Takes two optional arguments: onFulfilled and onRejected handlers


.catch()

- Attaches a callback for when the promise is rejected

- Returns a new promise (sugar syntax for .then(null, onRejected))

.finally()

- Attaches a callback that executes regardless of fulfillment or rejection

- Useful for cleanup operations that should always run

 

- Returns a new promise that preserves the original settlement state


How to Backup and Restore with pg_dump and mysqldump

0 👍
👎 0
 Database
 PostgreSQL
 MySQL

This tutorial guides you through backing up MySQL and PostgreSQL databases from the command line. While their native tools—mysqldump and pg_dump—share a similar purpose, their command syntax differs. We will cover the essential commands for both systems, highlighting their key similarities and differences. 

Backup MySQL / MariaDB Database

 

Export every table’s schema and existing records to an SQL executable script.


mysqldump -u username -p database_name > database.sql

 

This will export the specified table’s schema and records to an executable script.

 

 mysqldump -u username -p database_name table_name > db_table.sql

 

 

This will export the specified table’s data only(no schema).

 
mysqldump -u username -p --no-create-info database_name table_name > table_data.sql

 

 

This will export the specified table’s schema only(no data).


mysqldump -u username -p --no-data database_name table_name > table_schema.sql

 

Restore MySQL / MariaDB Database

 

 mysql -u username -p database_name < database.sql

 

 

Backup PostgreSQL Database

 

Export every table’s schema and existing records to an SQL executable script.

 

 pg_dump -U username database_name > database.sql

 

 

This will export both the specified table’s schema and data to an executable script.

 

 pg_dump -U username -t table_name database_name > table.sql

 

 

Only data (no schema):

 

 pg_dump -U username -a -t table_name database_name > table_data.sql

 

 

Only schema (no data):

 

 pg_dump -U username -s -t table_name database_name > table_schema.sql


Restore PostgreSQL Database

 

 psql -U username -d database_name -f database.sql