Passing an entire Class as a parameter within another Class - php

So far I feel like I've understood the concept and the advantages of OOP programming, and I've not really had any difficulties with understanding how to work with classes in PHP.
However, this has left me just a little confused. I think I may understand it, but I'm still uncertain.
I've been following a set of video tutorials (not sure on the rules on linking to outside resources, but I found them on youtube), and they're pretty self explanatory. Except, frustratingly, when the tutor decided to pass one class as a parameter within another class. At least I think that's what's happening;
Class Game
{
public function __construct()
{
echo 'Game Started.<br />';
}
public function createPlayer($name)
{
$this->player= New Player($this, $name);
}
}
Class Player
{
private $_name;
public function __construct(Game $g, $name)
{
$this->_name = $name;
echo "Player {$this->_name} was created.<br />";
}
}
Then I'm instantiating an object of the Game class and calling its method;
$game = new Game();
$game-> createPlayer('new player');
Rather frustratingly, the tutor doesn't really explain why he has done this, and hasn't displayed, as far as I can see, any calls in the code that would justify it.
Is the magic method constructor in Player passing in the Game class as a reference? Does this mean that the entire class is accessible within the Player class by reference? When referencing $this without pointing to any particular method or property, are you referencing the entire class?
If this is what is happening, then why would I want to do it? If I've created a Player inside my Game Class, then surely I can just access my Player Properties and Methods within the Game Class, right? Why would I want my Game Class inside my Player class as well? Could I then, for example, call createPlayer() within the Player class?
I apologise if my explanation has been at all confusing.
I guess my question boils down to; what is it that I'm passing as a parameter exactly, and why would I want to do it in every day OOP programming?

It's called type hinting and he's not passing the entire class as a parameter but ratter hinting the Class Player about the type of the first parameter
PHP 5 introduces type hinting. Functions are now able to force parameters to be objects (by specifying the name of the class in the function prototype), interfaces, arrays (since PHP 5.1) or callable (since PHP 5.4). However, if NULL is used as the default parameter value, it will be allowed as an argument for any later call.
(Extracted from php manual)
Does this mean that the entire class is accessible within the Player class by reference?
Not the entire class, but you can access the an instance of the class you are passing as a parameter

The method DOES expect to get the an object which is an instance of Game anything else, and it will error out.
You are passing an instance of Game just here: New Player($this, $name); The key word $this refers to the object instance you are in.
And last....I (and nobody else for that matter) has any idea why the author did it, as he is not using the Game instance after he passes it.
Why would u pass a Instance of a class?
Imagine a Class that accepts Users as input and according to some logic does something with them. (No comments in code, as function name and class name are supposed to be self-explanatory)
class User{
protected $name,$emp_type,$emp_id;
protected $department;
public function __construct($name,$emp_type,$emp_id){
$this->name = $name;
$this->emp_type = $emp_type;
$this->emp_id = $emp_id;
}
public function getEmpType(){
return $this->emp_type;
}
public function setDep($dep){
$this->department = $dep;
}
}
class UserHub{
public function putUserInRightDepartment(User $MyUser){
switch($MyUser->getEmpType()){
case('tech'):
$MyUser->setDep('tech control');
break;
case('recept'):
$MyUser->setDep('clercks');
break;
default:
$MyUser->setDep('waiting HR');
break;
}
}
}
$many_users = array(
0=>new User('bobo','tech',2847),
1=>new User('baba','recept',4443), many more
}
$Hub = new UserHub;
foreach($many_users as $AUser){
$Hub->putUserInRightDepartment($AUser);
}

/**
* Game class.
*/
class Game implements Countable {
/**
* Collect players here.
*
* #var array
*/
private $players = array();
/**
* Signal Game start.
*
*/
public function __construct(){
echo 'Game Started.<br />';
}
/**
* Allow count($this) to work on the Game object.
*
* #return integer
*/
public function Count(){
return count($this->players);
}
/**
* Create a player named $name.
* $name must be a non-empty trimmed string.
*
* #param string $name
* #return Player
*/
public function CreatePlayer($name){
// Validate here too, to prevent creation if $name is not valid
if(!is_string($name) or !strlen($name = trim($name))){
trigger_error('$name must be a non-empty trimmed string.', E_USER_WARNING);
return false;
}
// Number $name is also not valid
if(is_numeric($name)){
trigger_error('$name must not be a number.', E_USER_WARNING);
return false;
}
// Check if player already exists by $name (and return it, why create a new one?)
if(isset($this->players[$name])){
trigger_error("Player named '{$Name}' already exists.", E_USER_NOTICE);
return $this->players[$name];
}
// Try to create... this should not except but it's educational
try {
return $this->players[$name] = new Player($this, $name);
} catch(Exception $Exception){
// Signal exception
trigger_error($Exception->getMessage(), E_USER_WARNING);
}
// Return explicit null here to show things went awry
return null;
}
/**
* List Players in this game.
*
* #return array
*/
public function GetPlayers(){
return $this->players;
}
/**
* List Players in this game.
*
* #return array
*/
public function GetPlayerNames(){
return array_keys($this->players);
}
} // class Game;
/**
* Player class.
*/
class Player{
/**
* Stores the Player's name.
*
* #var string
*/
private $name = null;
/**
* Stores the related Game object.
* This allows players to point to Games.
* And Games can point to Players using the Game->players array().
*
* #var Game
*/
private $game = null;
/**
* Instantiate a Player assigned to a Game bearing a $name.
* $game argument is type-hinted and PHP makes sure, at compile time, that you provide a proper object.
* This is compile time argument validation, compared to run-time validations I do in the code.
*
* #param Game $game
* #param string $name
* #return Player
*/
public function __construct(Game $game, $name){
// Prevent object creation in case $name is not a string or is empty
if(!is_string($name) or !strlen($name = trim($name))){
throw new InvalidArgumentException('$name must be a non-empty trimmed string.');
}
// Prevent object creation in case $name is a number
if(is_numeric($name)){
throw new InvalidArgumentException('$name must not be a number.');
}
// Attach internal variables that store the name and Game
$this->name = $name;
$this->game = $game;
// Signal success
echo "Player '{$this->name}' was created.<br />";
}
/**
* Allow strval($this) to return the Player name.
*
* #return string
*/
public function __toString(){
return $this->name;
}
/**
* Reference back to Game.
*
* #return Game
*/
public function GetGame(){
return $this->game;
}
/**
* Allow easy access to private variable $name.
*
* #return string
*/
public function GetName(){
return $this->name;
}
} // class Player;
// Testing (follow main comment to understand this)
$game = new Game();
$player1 = $game->CreatePlayer('player 1');
$player2 = $game->CreatePlayer('player 2');
var_dump(count($game)); // number of players
var_dump($game->GetPlayerNames()); // names of players
Rewrote your code in a nicer way and added some missing variables that made that code pointless:
In player class you don't store the game.
In game class, you support only one player.
No error checking... anywhere.
Fixed all those plus:
Added exceptions (to prevent object creation)
Try{} catch(...){} Exception handling any OOP dev should know
Implemented Countable interface to allow count($game) players
Some more tricks that will give you a good read
Follow the comments and I hope your code will make more sense after you read it.

Related

Random String passed as the same string php

Trying to create a functional test using PHP with Behat and I want a random string for an email, but I want the string to be random every time a new test runs, but I want to pass the same string created to different tests as a parameter.
So if I generate a 10 digit string, I would like to generate the string and then pass it though other tests as the same 10 digit sequence
I'm new to PHP so I'm not exactly positive how to set it up, but here's what I have so far in my Behat context file
class FeatureContext implements Context {
private $MailPage;
private $registrationpage;
/**
* Initializes context.
*
* Every scenario gets its own context instance.
* You can also pass arbitrary arguments to the
* context constructor through behat.yml.
*/
public function __construct(MailPage $mailPage, RegistrationPage $registrationpage)
{
// Page obects injected directly in constructor with type hints.
$this->MailPage = $MailPage;
$this->registrationpage = $registrationpage;
}
/**
* #BeforeSuite
*/
public static function generateRandomString() {
// Generate random string for Email implementation.
$randomString = bin2hex(openssl_random_pseudo_bytes(10));
return $randomString;
}
/**
* #Given /^I register a temporary email address $/
*/
public function iRegisterATemporaryEmailAddress()
{
$this->MailPage->grabNewEmail(self::generateRandomEmail());
}
/**
* #Given /^I register a Developer account$/
*/
public function iRegisterADeveloperAccount()
{
$this->registrationpage->fillInFormDetails(self::generateRandomEmail());
}
The Problem I run into is that with the parameter as it is, It generates a different string every time it's called, but I only want it to generate it once for the entire suite. Any ideas?
1- Call your method from the constructor.
2- Save the generated value in a variable using this
private $randomString ;
public function __construct(MailPage $mailPage, RegistrationPage $registrationpage)
{
//your code
$this->randomString = $this->generateRandomString();
}
3- To use this variable you can call it inside your class methods like this $this->randomString.
Classes which have a constructor method call this method on each
newly-created object, so it is suitable for any initialization that
the object may need before it is used.

private property access with setter from constructor vs direct access from constructor

In TrainBoardingCard we have setTrainCode is it ok to use $this->trainCode = $trainCode inside constructor or we shoud always use setTrainCode like $this->setTrainCode($trainCode); as it could have some logic in future.
For both case what are the pros and cons? please let us know your preference with reasons.
class TrainBoardingCard extends BoardingCard
{
/**
* #var string
*/
private $trainCode;
/**
* #param string $trainCode
*/
public function __construct(string $trainCode)
{
$this->trainCode = $trainCode;
}
/**
* #return string
*/
public function getTrainCode(): string
{
return $this->trainCode;
}
/**
* #param string $trainCode
*/
public function setTrainCode(string $trainCode)
{
$this->trainCode = $trainCode;
}
}
It depends.
You could say there are two different schools of thought and they both deal with both setters and constructors.
The object must be created already valid state. This state can be changed with atomic operation from one valid state to another. This means, that you class doesn't actually have simple setters per se.
$client = new Client(
new FullName($name, $surname),
new Country($country);
new Address($city, street, $number));
// do something
$client->changeLocation(
new Country('UK'),
new Address('London', 'Downing St.', '10'));
Constructor is used only do pass in dependencies and not to impart state. The object's state by default is blank and it gets changed only by using setters externally.
$client new Client();
$client->setId(14);
$mapper = new DataMapper(new PDO('...'), $config);
$mapper->fetch($client);
if ($client->getCity() === 'Berlin') {
$client->setCity('London');
$mapper->store($client);
}
Or you can have a mix or both, but that would cause some confusion.
Not sure if this will make it better for you or worse :)

Data Mapper pattern, exceptions, and handling user-provided data

In applying the Data Mapper pattern, the model (Domain Model in my case) is responsible for business logic where possible, rather than the mapper that saves the entity to the database.
Does it seem reasonable to build a separate business logic validator for processing user-provided data outside of the model?
An example is below, in PHP syntax.
Let's say we have an entity $person. Let's say that that entity has a property surname which can not be empty when saved.
The user has entered an illegal empty value for surname. Since the model is responsible for encapsulating business logic, I'd expect $person->surname = $surname; to somehow say that the operation was not successful when the user-entered $surname is an empty string.
It seems to me that $person should throw an exception if we attempt to fill one of its properties with an illegal value.
However, from what I've read on exceptions "A user entering 'bad' input is not an exception: it's to be expected." The implication is to not rely on exceptions to validate user data.
How would you suggest approaching this problem, with the balance between letting the Domain Model define business logic, yet not relying on exceptions being thrown by that Domain Model when filling it with user-entered data?
A Domain Model is not necessarily an object that can be directly translated to a database row.
Your Person example does fit this description, and I like to call such an object an Entity (adopted from the Doctrine 2 ORM).
But, like Martin Fowler describes, a Domain Model is any object that incorporates both behavior and data.
a strict solution
Here's a quite strict solution to the problem you describe:
Say your Person Domain Model (or Entity) must have a first name and last name, and optionally a maiden name. These must be strings, but for simplicity may contain any character.
You want to enforce that whenever such a Person exists, these prerequisites are met. The class would look like this:
class Person
{
/**
* #var string
*/
protected $firstname;
/**
* #var string
*/
protected $lastname;
/**
* #var string|null
*/
protected $maidenname;
/**
* #param string $firstname
* #param string $lastname
* #param string|null $maidenname
*/
public function __construct($firstname, $lastname, $maidenname = null)
{
$this->setFirstname($firstname);
$this->setLastname($lastname);
$this->setMaidenname($maidenname);
}
/**
* #param string $firstname
*/
public function setFirstname($firstname)
{
if (!is_string($firstname)) {
throw new InvalidArgumentException('Must be a string');
}
$this->firstname = $firstname;
}
/**
* #return string
*/
public function getFirstname()
{
return $this->firstname;
}
/**
* #param string $lastname
*/
public function setLastname($lastname)
{
if (!is_string($lastname)) {
throw new InvalidArgumentException('Must be a string');
}
$this->lastname = $lastname;
}
/**
* #return string
*/
public function getLastname()
{
return $this->lastname;
}
/**
* #param string|null $maidenname
*/
public function setMaidenname($maidenname)
{
if (!is_string($maidenname) or !is_null($maidenname)) {
throw new InvalidArgumentException('Must be a string or null');
}
$this->maidenname = $maidenname;
}
/**
* #return string|null
*/
public function getMaidenname()
{
return $this->maidenname;
}
}
As you can see there is no way (disregarding Reflection) that you can instantiate a Person object without having the prerequisites met.
This is a good thing, because whenever you encounter a Person object, you can be a 100% sure about what kind of data you are dealing with.
Now you need a second Domain Model to handle user input, lets call it PersonForm (because it often represents a form being filled out on a website).
It has the same properties as Person, but blindly accepts any kind of data.
It will also have a list of validation rules, a method like isValid() that uses those rules to validate the data, and a method to fetch any violations.
I'll leave the definition of the class to your imagination :)
Last you need a Controller (or Service) to tie these together. Here's some pseudo-code:
class PersonController
{
/**
* #param Request $request
* #param PersonMapper $mapper
* #param ViewRenderer $view
*/
public function createAction($request, $mapper, $view)
{
if ($request->isPost()) {
$data = $request->getPostData();
$personForm = new PersonForm();
$personForm->setData($data);
if ($personForm->isValid()) {
$person = new Person(
$personForm->getFirstname(),
$personForm->getLastname(),
$personForm->getMaidenname()
);
$mapper->insert($person);
// redirect
} else {
$view->setErrors($personForm->getViolations());
$view->setData($data);
}
}
$view->render('create/add');
}
}
As you can see the PersonForm is used to intercept and validate user input. And only if that input is valid a Person is created and saved in the database.
business rules
This does mean that certain business logic will be duplicated:
In Person you'll want to enforce business rules, but it can simple throw an exception when something is off.
In PersonForm you'll have validators that apply the same rules to prevent invalid user input from reaching Person. But here those validators can be more advanced. Think off things like human error messages, breaking on the first rule, etc. You can also apply filters that change the input slightly (like lowercasing a username for example).
In other words: Person will enforce business rules on a low level, while PersonForm is more about handling user input.
more convenient
A less strict approach, but maybe more convenient:
Limit the validation done in Person to enforce required properties, and enforce the type of properties (string, int, etc). No more then that.
You can also have a list of constraints in Person. These are the business rules, but without actual validation code. So it's just a bit of configuration.
Have a Validator service that is capable of receiving data along with a list of constraints. It should be able to validate that data according to the constraints. You'll probably want a small validator class for each type of constraint. (Have a look at the Symfony 2 validator component).
PersonForm can have the Validator service injected, so it can use that service to validate the user input.
Lastly, have a PersonManager service that's responsible for any actions you want to perform on a Person (like create/update/delete, and maybe things like register/activate/etc). The PersonManager will need the PersonMapper as dependency.
When you need to create a Person, you call something like $personManager->create($userInput); That call will create a PersonForm, validate the data, create a Person (when the data is valid), and persist the Person using the PersonMapper.
The key here is this:
You could draw a circle around all these classes and call it your "Person domain" (DDD). And the interface (entry point) to that domain is the PersonManager service. Every action you want to perform on a Person must go through PersonManager.
If you stick to that in your application, you should be safe regarding to ensuring business rules :)
I think the statement "A user entering 'bad' input is not an exception: it's to be expected." is debatable...
But if you don't want to throw an exception, why don't you create an isValid(), or getValidationErrors() method?
You can then throw an exception, if someone tries to save an invalid entity to the database.
Your domain requires that when creating a person, you will provide a first name and a surname. The way I normally approach this is by validating the input model, an input model might look like;
class PersonInput
{
var $firstName;
var $surname;
public function isValid() {
return isset($this->firstName) && isset($this->surname);
}
}
This is really a guard, you can put these rules in your client side code as well to try and prevent this scenario, or you can you return from your post with an invalid person message. I don't see this as an exception, more along the lines of "to be expected" which is why I write the guard code. Your entry into your domain now might look like;
public function createPerson(PersonInput $input) {
if( $input->isValid()) {
$model->createPerson( $input->firstName, $input->surname);
return 'success';
} else {
return 'person must comtain a valid first name and surname';
}
}
This is just my opinion, and how I go about keeping my validation logic away from the domain logic.
I think your design in which the $person->surname = ''; should raise an error or exception could be simplified.
Return the error once
You dont want to catch errors all the time when assigning each value, you want a simple one-stop solution like $person->Valididate() that looks at the current values. Then when you'd call a ->Save() function, it could automatically call ->Validate() first and simply return False.
Return the error details
But returning False, or even an errorcode is often not sufficient: you want the 'who? why?' details. So lets use a class instance to contain the details, i call it ItemFieldErrors. Its passed to Save() and only looked at when Save() returns False.
public function Validate(&$itemFieldErrors = NULL, $aItem = NULL);
Try this complete ItemFieldErrors implementation. An array would suffice, but i found this more structured, versatile and self-documenting. You could always pass and parse the error details more intelligently anywhere/way you like, but often (if not always..) just outputting the asText() summary would do.
/**
* Allows a model to log absent/invalid fields for display to user.
* Can output string like "Birthdate is invalid, Surname is missing"
*
* Pass this to your Validate() model function.
*/
class ItemFieldErrors
{
const FIELDERROR_MISSING = 1;
const FIELDERROR_INVALID = 2;
protected $itemFieldErrors = array();
function __construct()
{
$this->Clear();
}
public function AddErrorMissing($fieldName)
{
$this->itemFieldErrors[] = array($fieldName, ItemFieldErrors::FIELDERROR_MISSING);
}
public function AddErrorInvalid($fieldName)
{
$this->itemFieldErrors[] = array($fieldName, ItemFieldErrors::FIELDERROR_INVALID);
}
public function ErrorCount()
{
$count = 0;
foreach ($this->itemFieldErrors as $error) {
$count++;
}
unset($error);
return $count;
}
public function Clear()
{
$this->itemFieldErrors = array();
}
/**
* Generate a human readable string to display to user.
* #return string
*/
public function AsText()
{
$s = '';
$comma = '';
foreach($this->itemFieldErrors as $error) {
switch ($error[1]) {
case ItemFieldErrors::FIELDERROR_MISSING:
$s .= $comma . sprintf(qtt("'%s' is absent"), $error[0]);
break;
case ItemFieldErrors::FIELDERROR_INVALID:
$s .= $comma . sprintf(qtt("'%s' is invalid"), $error[0]);
break;
default:
$s .= $comma . sprintf(qtt("'%s' has unforseen issue"), $error[0]);
break;
}
$comma = ', ';
}
unset($error);
return $s;
}
}
Then ofcourse there is $person->Save() that needs to receive it so it can pass it through to Validate(). In my code, whenever i 'load' data from the user (form submission) the same Validate() is called already, not only when saving.
The model, would do this:
class PersonModel extends BaseModel {
public $item = array();
public function Validate(&$itemFieldErrors = NULL, $aItem = NULL) {
// Prerequisites
if ($itemFieldErrors === NULL) { $itemFieldErrors = new ItemFieldErrors(); }
if ($aItem === NULL) { $aItem = $this->item; }
// Validate
if (trim($aItem['name'])=='') { $itemFieldErrors->AddErrorMissing('name'); }
if (trim($aItem['surname'])=='') { $itemFieldErrors->AddErrorMissing('surname'); }
if (!isValidDate($aItem['birthdate'])) { $itemFieldErrors->AddErrorInvalid('birthdate'); }
return ($itemFieldErrors->ErrorCount() == 0);
}
public function Load()..
public function Save()..
}
This simple model would hold all data in $item, so it simply exposes fields as $person->item['surname'].

Does this PHPUnit test make any sense (or I'm testing the framework/PHP)?

I'm just beginning with PHPUnit and TDD.
Among others, I can't really answer to this question: Is this a good test? Am i actually testing my code or something already tested (i.e. the framework or PHP itself)?
Little example, this is the test subject:
class DateMax extends Constraint
{
/**
* #var string
*/
public $limit;
/**
* #var string
*/
private $invalidLimit = 'Option "limit" should be a valid date/time string.';
public function __construct($options = null)
{
parent::__construct($options);
if(false === strtotime($this->limit)) {
throw new InvalidOptionsException($this->invalidLimit, ['limit']);
}
}
}
I want to test that InvalidOptionsException is expected when invalid "limit" options are passed, otherwise $constraint->limit holds the correct value:
/**
* #dataProvider getInvalidLimits
* #expectedException InvalidOptionsException
*/
public function testInvalidLimits($testLimit)
{
new DateMax($testLimit);
}
/**
* #dataProvider getValidLimits
*/
public function testValidLimits($testLimit)
{
$constraint = new DateMax($testLimit);
$this->assertEquals($testLimit, $constraint->limit);
}
/**
* #return array[]
*/
public function getInvalidLimits()
{
return array(array('invalid specification'), array('tomorr'));
}
/**
* #return array[]
*/
public function getValidLimits()
{
return array(array('now'), array('+1 day'),array('last Monday'));
}
So question is does this make any sense or I'm testing the framework/PHP itself?
Of course it has sense, because you override constructor of Constraint class and there is possibility that you'll break something inside it. So basing on your constructor logic basically you want to test two things:
check if you call parent's constructor with the same options, exactly once (you can use mock for this purpose, you don't care about setting appropriate limit value, because this should be tested in Constraint class)
check if an appropriate exception has been thrown when limit has wrong value (eg. null)
edit: Some use case where first test will be useful may be this one:
Let say at some moment you want to extend your DateMax constructor in this way:
public function __construct($options = null)
{
$this->optionsWithDecrementedValues = $this->doWeirdThings($options);
parent::__construct($options);
if(false === strtotime($this->limit)) {
throw new InvalidOptionsException($this->invalidLimit, ['limit']);
}
}
but for example you didn't notice that method "doWeirdThings" takes a reference as argument. So in fact it changes $options value, what you didn't expect, but first test fails so you won't miss it.

doctrine2 odm for mongodb isn't saving the clone's nested objects

so i have a school, each school has multiple bell schedules and each schedule has details:
school (document)
-- bell schedule (embedded document)
---- bell schedule details (embedded document)
when i clone the school object and print_r the school, it comes back with the proper objects in the clone. however, when i try to persist the school, it doesn't save the details properly. is there something that I need to do in order for this to work properly? is there a flag I need to set or something?
what im trying to do is:
$school2 = clone $school1;
$dm->persist($school2);
$dm->flush();
---- classes ----
/**
* #MongoDB\Document(collection="schools")
*/
class School
{
/**
* #MongoDB\EmbedMany
*/
protected $bell_schedules = array();
public function addBellSchedules(BellSchedule $bellSchedules)
{
$this->bell_schedules[] = $bellSchedules;
}
public function getBellSchedules()
{
return $this->bell_schedules;
}
public function setBellSchedules(\Doctrine\Common\Collections\ArrayCollection $bell_schedules)
{
$this->bell_schedules = $bell_schedules;
return $this;
}
}
/**
* #MongoDB\EmbeddedDocument
*/
class BellSchedule
{
/**
* #MongoDB\EmbedMany
*/
private $bell_schedule_details
public function getBellScheduleDetails()
{
return $this->bell_schedule_details;
}
public function setBellScheduleDetails(\Doctrine\Common\Collections\ArrayCollection $bell_schedule_details)
{
$this->bell_schedule_details = $bell_schedule_details;
return $this;
}
}
/**
* #MongoDB\EmbeddedDocument
*/
class BellScheduleDetail
{
private $period;
private $label;
}
Your #EmbedMany annotations are missing the targetDocument attribute, which should correspond to the class name of the embedded object(s). See the annotation reference for more information. Also, you are missing field mappings for the BellScheduleDetail class. You may want to use #String for those fields.
Lastly, I would advise initializing your EmbedMany and ReferenceMany fields as ArrayCollection instances rather than empty arrays. That way you can always expect the property to be a Collection implementation (either ArrayCollection or PersistentCollection). It may not make much difference in your case (using the [] operator), but it can come in handy if you find yourself doing other array operations on the property.

Categories