Php object containing objects

Objects

PHP is an object oriented language, although it does not have to be used as one, since most PHP functions are not object oriented.

In object oriented programming, a class is a definition of an object, whereas an object is an instance of an object, meaning that from one class you can create many objects.

For example, let’s define a class of a student.

class Student < // constructor public function __construct($first_name, $last_name) < $this->first_name = $first_name; $this->last_name = $last_name; > public function say_name() < echo "My name is " . $this->first_name . " " . $this->last_name . ".\n"; > > $alex = new Student("Alex", "Jones"); $alex->say_name(); 

Let’s analyze the code. Notice that the Student class has a constructor function, which is executed when the object is created. The constructor receives arguments which are later provided when constructing the object with the new keyword.

After we have constructed the object into the variable $alex we can now use the object’s methods.

We implemented an object method say_name , which prints out the name of the student. Notice that the say_name function does not receive any arguments, but it does have access to the first and last name of the student, because they were previously defined in the constructor.

Here are some important definitions related to objects:

  • Classes define how objects behave. Classes do not contain data.
  • Objects are instances of classes, which contain data.
  • Members are variables that belong to an object.
  • Methods are functions that belong to an object, and have access to its members.
  • Constructor is a special method that is executed when an object is created.

Inheritance

The most important feature of object oriented programming is inheritance. This feature allows us to reuse code we’ve written and extend it. For example, let’s say we want to be able to define a math student, which also knows how to sum two numbers.

class Student < // constructor public function __construct($first_name, $last_name) < $this->first_name = $first_name; $this->last_name = $last_name; > public function say_name() < echo "My name is " . $this->first_name . " " . $this->last_name . ".\n"; > > $alex = new Student("Alex", "Jones"); $alex->say_name(); class MathStudent extends Student < function sum_numbers($first_number, $second_number) < $sum = $first_number + $second_number; echo $this->first_name . " says that " . $first_number . " + " . $second_number . " is " . $sum; > > $eric = new MathStudent("Eric", "Chang"); $eric->say_name(); $eric->sum_numbers(3, 5); 

Notice that Eric’s object also has the same constructor and the say_name function, in addition to a new method called sum_numbers , which causes Eric to calculate the sum of two numbers. Also notice that the new function has access to the same members we have previously defined in the Student class ( first_name , last_name ).

Public and private functions

We can use the public and private modifiers respectively to define functions which can be accessed from outside the object or not, for encapsulation purposes. This allows to better define how objects should be used, to separate between functions which are used for internal use, as opposed to an external interface.

class Student < // constructor should be public public function __construct($first_name, $last_name) < $this->first_name = $first_name; $this->last_name = $last_name; > // for external use public function say_name() < echo "My name is " . $this->full_name() . "\n"; > // for internal use private function full_name() < return $this->first_name . " " . $this->last_name; > > $alex = new Student("Alex", "Jones"); $alex->say_name(); // this will not work // echo $alex->full_name(); 

Exercise

Create a class called Car with a constructor that receives the brand and make year of the car, and a function called print_details that prints out the details of the car.

Читайте также:  Java add method to class

For example, for a 2006 Toyota car, the following line would be printed out:

This car is a 2006 Toyota.

Источник

The SplObjectStorage class

The SplObjectStorage class provides a map from objects to data or, by ignoring data, an object set. This dual purpose can be useful in many cases involving the need to uniquely identify objects.

Class synopsis

Examples

Example #1 SplObjectStorage as a set

// As an object set
$s = new SplObjectStorage ();

$o1 = new stdClass ;
$o2 = new stdClass ;
$o3 = new stdClass ;

$s -> attach ( $o1 );
$s -> attach ( $o2 );

var_dump ( $s -> contains ( $o1 ));
var_dump ( $s -> contains ( $o2 ));
var_dump ( $s -> contains ( $o3 ));

var_dump ( $s -> contains ( $o1 ));
var_dump ( $s -> contains ( $o2 ));
var_dump ( $s -> contains ( $o3 ));
?>

The above example will output:

bool(true) bool(true) bool(false) bool(true) bool(false) bool(false)

Example #2 SplObjectStorage as a map

// As a map from objects to data
$s = new SplObjectStorage ();

$o1 = new stdClass ;
$o2 = new stdClass ;
$o3 = new stdClass ;

$s [ $o1 ] = «data for object 1» ;
$s [ $o2 ] = array( 1 , 2 , 3 );

if (isset( $s [ $o2 ])) var_dump ( $s [ $o2 ]);
>
?>

The above example will output:

array(3) < [0]=>int(1) [1]=> int(2) [2]=> int(3) >

Table of Contents

  • SplObjectStorage::addAll — Adds all objects from another storage
  • SplObjectStorage::attach — Adds an object in the storage
  • SplObjectStorage::contains — Checks if the storage contains a specific object
  • SplObjectStorage::count — Returns the number of objects in the storage
  • SplObjectStorage::current — Returns the current storage entry
  • SplObjectStorage::detach — Removes an object from the storage
  • SplObjectStorage::getHash — Calculate a unique identifier for the contained objects
  • SplObjectStorage::getInfo — Returns the data associated with the current iterator entry
  • SplObjectStorage::key — Returns the index at which the iterator currently is
  • SplObjectStorage::next — Move to the next entry
  • SplObjectStorage::offsetExists — Checks whether an object exists in the storage
  • SplObjectStorage::offsetGet — Returns the data associated with an object
  • SplObjectStorage::offsetSet — Associates data to an object in the storage
  • SplObjectStorage::offsetUnset — Removes an object from the storage
  • SplObjectStorage::removeAll — Removes objects contained in another storage from the current storage
  • SplObjectStorage::removeAllExcept — Removes all objects except for those contained in another storage from the current storage
  • SplObjectStorage::rewind — Rewind the iterator to the first storage element
  • SplObjectStorage::serialize — Serializes the storage
  • SplObjectStorage::setInfo — Sets the data associated with the current iterator entry
  • SplObjectStorage::unserialize — Unserializes a storage from its string representation
  • SplObjectStorage::valid — Returns if the current iterator entry is valid
Читайте также:  Замена двух переменных местами python

User Contributed Notes 12 notes

Note some inconsistent/surprising behavior in SplObjectStorage to preserve backwards compatibility. You can’t properly use foreach with key/value syntax.

$spl = new SplObjectStorage ();
$keyForA = new StdClass ();
$keyForB = new StdClass ();
$spl [ $keyForA ] = ‘value a’ ;
$spl [ $keyForB ] = ‘value b’ ;
foreach ( $spl as $key => $value )
// $key is NOT an object, $value is!
// Must use standard array access to get strings.
echo $spl [ $value ] . «\n» ; // prints «value a», then «value b»
>
// it may be clearer to use this form of foreach:
foreach ( $spl as $key )
// $key is an object.
// Use standard array access to get values.
echo $spl [ $key ] . «\n» ; // prints «value a», then «value b»
>
?>

See https://bugs.php.net/bug.php?id=49967

SplObjectStorage class can be nicely used in Observer pattern, for example:

class Subject implements \ SplSubject
private $observers ;

public function __construct ()
$this -> observers = new \ SplObjectStorage ;
>

public function attach (\ SplObserver $observer )
$this -> observers -> attach ( $observer );
>

public function detach (\ SplObserver $observer )
$this -> observers -> detach ( $observer );
>

public function notify ()
foreach ( $this -> observers as $observer ) $observer -> update ( $this );
>
>
>
?>

Keep in mind that foreach() will copy your array before iterating, SplObjectStorage does not. If you have a sub call within an iteration that also calls foreach() on the object storage again, the iterator position collides!

To be safe use:
foreach(clone $myStorage as $obj )

Please note that SplObjectStorage has a Bug introduced with 5.4.0, breaking object lookup in cloned instances of derived classes that overwrite getHash().

Example:
class MyObjectStorage extends SplObjectStorage // Overwrite getHash() with just some (working) test-method
public function getHash ( $object ) < return get_class ( $object ); >
>

Читайте также:  Run java jar from command

$list = new MyObjectStorage (); // No issues if using «new SplObjectStorage()»
$list -> attach (new TestObject ());

foreach( $list as $x ) var_dump ( $list -> offsetExists ( $x )); // TRUE

$list2 = clone $list ;
foreach( $list2 as $x ) var_dump ( $list2 -> offsetExists ( $x )); // FALSE
?>

/**
* For simple use cases (where you want to keep objects in a map)
* I would suggest to stick to an plain old array. Just use the object
* hash as array key.
*/
$entity1 = new stdClass ();
$entity2 = new stdClass ();
$entities = [];
$entities [ spl_object_hash ( $entity1 )] = $entity1 ;
$entities [ spl_object_hash ( $entity2 )] = $entity2 ;

// object hashes are hard to distinguish so you could run a hash function
// on them for better readability.
$entities [ md5 ( spl_object_hash ( $entity1 ))] = $entity1 ;
$entities [ md5 ( spl_object_hash ( $entity2 ))] = $entity2 ;

For anyone having issues with SplObjectStorages containing corrupt member variables after garbage collection (FatalErrorException after serializing): we used following fix to great effect

class FixedSplObjectStorage extends SplObjectStorage

public function serialize ()
$goodPortion = ‘N;;m:a:0:<>‘ ;
$startKey = ‘N;;m:a:’ ;

$serialized = parent :: serialize ();

$startPos = strpos ( $serialized , $startKey );

if ( $startPos !== false ) $serialized = substr_replace ( $serialized , $goodPortion , $startPos , — 1 );

I needed to merge SplObjectStorages.
// As an object set
$SplObjectStorage_1 = new SplObjectStorage ();

$object1 = new StdClass ;
$object1 -> attr = ‘obj 1’ ;
$object2 = new StdClass ;
$object2 -> attr = ‘obj 2’ ;
$object3 = new StdClass ;
$object3 -> attr = ‘obj 3’ ;

$SplObjectStorage_1 -> attach ( $object1 );
$SplObjectStorage_1 -> attach ( $object2 );
$SplObjectStorage_1 -> attach ( $object3 );

// Another one object set
$SplObjectStorage_2 = new SplObjectStorage ();

$object4 = new StdClass ;
$object4 -> attr = ‘obj 4’ ;
$object5 = new StdClass ;
$object5 -> attr = ‘obj 5’ ;
$object6 = new StdClass ;
$object6 -> attr = ‘obj 6’ ;

$SplObjectStorage_2 -> attach ( $object4 );
$SplObjectStorage_2 -> attach ( $object5 );
$SplObjectStorage_2 -> attach ( $object6 );

/**
* Merge SplObjectStorage
*
* @param how many SplObjectStorage params as you want
* @return SplObjectStorage
*/
function mergeSplObjectStorage ()

$buffer = new SplObjectStorage ();

if( func_num_args () > 0 ) $args = func_get_args ();
foreach ( $args as $objectStorage ) foreach( $objectStorage as $object ) if( is_object ( $object ) ) $buffer -> attach ( $object );
>
>
>
>
else return FALSE ;
>
return $buffer ;
>

$merge = mergeSplObjectStorage ( $SplObjectStorage_1 , $SplObjectStorage_2 );

$merge -> rewind ();
while( $merge -> valid ()) $object = $merge -> current ();
var_dump ( $object );
$merge -> next ();
>
?>
Will ouput :
object(stdClass)#2 (1) [«attr»]=>
string(5) «obj 1»
>
object(stdClass)#3 (1) [«attr»]=>
string(5) «obj 2»
>
object(stdClass)#4 (1) [«attr»]=>
string(5) «obj 3»
>
object(stdClass)#6 (1) [«attr»]=>
string(5) «obj 4»
>
object(stdClass)#7 (1) [«attr»]=>
string(5) «obj 5»
>
object(stdClass)#8 (1) [«attr»]=>
string(5) «obj 6»
>

Источник

Оцените статью