PHP Null Object Design Pattern

From wikipedia: In object-oriented computer programming, a null object is an object with no referenced value or with defined neutral (“null”) behavior. This pattern is used to deal with the absence of an object by providing an alternative that indicates this absence. In short the null object replaces the checking for null values. These classes also adhere to the Open-Close Principle.

This pattern changes:

if (!is_null($obj)) { $obj->callMethod(); }
to just 
$obj->callMethod();

– Client code is simplified
– Reduces the chance of null pointer exceptions
– Fewer conditionals require less test cases


execute();
    }
}

$outputCommand = new OutputCommand();
$fileCommand = new FileCommand();
$app = new Application();

// Echo predefined string
$application->run($outputCommand); // Output from the command

// Create a file and append string to it
$application->run($fileCommand);

// Do nothing
$application->run();

PHP Referential Transparency

In functional programs, variables once defined do not change their value throughout the program. Functional programs do not have assignment statements. If we have to store some value, we define new variables instead. This eliminates any chances of side effects because any variable can be replaced with its actual value at any point of execution. State of any variable is constant at any instant.


$value = 12;
$value = $value + 1 // this changes the value assigned to the variable $value.
          // The expression is not referentially transparent. 

$new_value  = $value + 1 // assigns a value to the variable $new_value.
          // The expression is referentially transparent. 

Referentially transparent functions are pure functions with immutable data structures.

Redirect after login to the requested page

When a user requests a protected page after being logged out (expired session)

// A check on all protected pages that redirects to login. (middleware or include file)
if (!$_SESSION['logged_in']) { // set when a user logs in
    $_SESSION["login_redirect"] = $_SERVER["PHP_SELF"]; // save the page
    header("Location: login.php"); // go to login form
    exit;
}

If login is successful redirect to the intended page if saved in the session or just load the members home page

/* Login is successful */
if ($_SESSION['logged_in']) {
    if (isset($_SESSION["login_redirect"]) {
        header("Location: " . $_SESSION["login_redirect"]);
        unset($_SESSION["login_redirect"]);
    }
    else {
        header("Location: members.php");
        exit();
    }
}

Convert a PHP object to an associative array

// start
class MyClass {

	public $var1 = 1;
	public $var2 = 2;
	public static $var3 = 3;
	protected $var4 = 4;
	private $var5 = 5;
	
	public function toArray() {
		return (array) get_object_vars($this);
	}
} 

function toArray($object) {
	//$reflectionClass = new ReflectionClass(get_class($object));
	$reflectionClass = new ReflectionObject($object);
    $array = [];
    foreach ($reflectionClass->getProperties() as $property) {
        $property->setAccessible(true);
        $array[$property->getName()] = $property->getValue($object);
        $property->setAccessible(false);
    }
    return $array;
}

$object = new MyClass(); 
$array = toArray($object);
$array2 = $object->toArray();
print_r($array2);	// Inaccessible NO static
print_r($array);	// Inaccessible and static

$obArray = [];
foreach($object as $ob){
	$obArray[] = $ob;
}
print_r($obArray);	// public only


Array
(
    [var1] => 1
    [var2] => 2
    [var4] => 4
    [var5] => 5
)
Array
(
    [var1] => 1
    [var2] => 2
    [var3] => 3
    [var4] => 4
    [var5] => 5
)
Array
(
    [0] => 1
    [1] => 2
)

Merging PHP Objects

Given two objects of same class, merge both objects into a single object.


class MyClass {} 
  
$objectA = new MyClass(); 
$objectA->a = 1; 
$objectA->b = 2; 
$objectA->d = 3; 
  
$objectB = new MyClass(); 
$objectB->d = 4; 
$objectB->e = 5; 
$objectB->f = 6; 
 
// Using array_merge
$obj_merged = (object) array_merge((array) $objectA, (array) $objectB); 
print_r($obj_merged);
stdClass Object
(
    [a] => 1
    [b] => 2
    [d] => 4
    [e] => 5
    [f] => 6
)

// Using array union operator
$obj_union = (object)((array) $objectA +(array) $objectB);        
print_r($obj_union);
stdClass Object
(
    [a] => 1
    [b] => 2
    [d] => 3
    [e] => 5
    [f] => 6
)

PHP array_merge and array union operator

In PHP you can combine arrays using the union operator (+) or the array_merge function.

$ar1 = [
   0  => '1-0',
  'a' => '1-a',
  'b' => '1-b'
];


$ar2 = [
   0  => '2-0',
   1  => '2-1',
  'b' => '2-b',
  'c' => '2-c'
];

print_r($ar1+$ar2);

print_r(array_merge($ar1,$ar2));

The + operator returns the right-hand array appended to the left-hand array; for keys that exist in both arrays, the elements from the left-hand array will be used, and the matching elements from the right-hand array will be ignored.

Array
(
    [0] => 1-0
    [a] => 1-a
    [b] => 1-b
    [1] => 2-1
    [c] => 2-c
)

array_merge() If the input arrays have the same string keys, then the later value for that key will overwrite the previous one. If, however, the arrays contain numeric keys, the later value will not overwrite the original value, but will be appended.

Array
(
    [0] => 1-0
    [a] => 1-a
    [b] => 2-b
    [1] => 2-0
    [2] => 2-1
    [c] => 2-c
)

PHP iterate through an array in reverse

To reverse the items in an array you have two methods of achieving this
array_reverse()

$array = [1,2,3,4,5,6,7,8,9];

$rev = array_reverse($array);

foreach($rev as $val) {
    print $val;
}

end() & prev() rewind

   $array = [1,2,3,4,5,6,7,8,9];
    print end($array);

    while($val = prev($array)) {
        print $val;
    }

will both print:
987654321

PHP: self vs $this

Self:
-self refers to the current class
-self can be used to call static functions and reference static member variables
-self can be used inside static functions
-self can also turn off polymorphic behavior by bypassing the vtable

$this:
-$this refers to the current object
-$this can be used to call object functions
-$this should not be used to call static member variables. Use self instead.
-$this can not be used inside static functions

self = Current class.
static = Current class in runtime.
parent = Parent class.

class Test
{
    private $baz = 1;

	public static function foo() 
    { 
        echo "foo\n"; 
    }

  	public function bar()
  	{
    	echo "bar\n";
	    $this->foo();
    	$this::foo();
	    self::foo();
        self::baz();
  	}

	public function baz()
    {
        printf("baz = %d\n", $this->baz);
    }
}

$test = new Test;
$test->bar(); // bar foo foo foo baz = 1 


PHP manual
Declaring class properties or methods as static makes them accessible without needing an instantiation of the class. A property declared as static can not be accessed with an instantiated class object (though a static method can).

Test::foo(); // foo

Is the same as

$test->foo(); // foo

PHP Errors and Logging Settings

PHP .ini file

Locate the section “Error handling and logging”, This directive informs PHP of which errors, warnings and notices you would like it to take action for.

You will see and be able to alter these config settings

error_reporting = E_ALL
display_errors = On
display_startup_errors = On
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
track_errors = Off
html_errors = On

Error Reporting

This directive informs PHP of which errors, warnings and notices you would like it to take action for.

To show only errors, (no warnings or notices)

error_reporting = E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR

If you do only display errors, you will not be able to see common run time notices and warnings such as

NOTICE Undefined variable: var on line number 2

Display Errors

Just because error reporting is turned on, you wont be able to see the errors unless the display_errors flag has the on value

To show only errors, (no warnings or notices)

display_errors = On