dissociated variables in array - php

I have a problem with php variables. I use a code that looks like this:
for($i = 0; $i <= $nbRecurrence; $i++) {
$res = new Reservation();
$res->setDateDebut($DateDebut->add(new \DateInterval('P1D')));
$res->setDateFin($DateFin->add(new \DateInterval('P1D')));
$lesRes[] = $res;
$this->app['orm.ems']['gestionReservationAuto']->persist($res);
$this->app['orm.ems']['gestionReservationAuto']->flush();
}
The problem is that although I adds each element in the array, but when I use a var_dump for analysis, all $res in $lesRes are identical. Registered data is yet different in the database ...
How can I do to have an array with $res that do not like?
(if I make a request to have the items I just added in database, I have the same problem, I have an array of x elements $res, which are all identical.)

I guess $DateDebut is a DateTime object.
I also guess that Reservation::setDateDebut() looks something like:
class Reservation
{
private $dateDebut;
public function setDateDebut(DateTime $dateDebut)
{
$this->dateDebut = $dateDebut;
}
}
And let's write again the code that uses it:
$res = new Reservation();
$res->setDateDebut($DateDebut->add(new \DateInterval('P1D')));
What you miss is the fact that DateTime::add() does not create a new DateTime object but returns a reference to the current object (i.e. return $this;).
This means on each iteration you change the value of object $DateDebut then you pass it to Reservation::setDateDebut() which also doesn't make a copy of it but just links to the object it gets as argument.
After the loop you still have only two instances of DateTime; one of them is accessible through the variable $DateDebut and the members $dateDebut of all the Reservation objects created during the loop. The other instance is $DateFin and the same discussion is valid for it too.
Your code is a victim of variables aliasing.
How to fix it:
You need to create copies of $DateDebut somewhere, either in the loop code (and pass the copies to Reservation::setDateDebut()) or in the body of Reservation::setDateDebut():
// Either
$res->setDateDebut(clone $DateDebut->add(new \DateInterval('P1D')));
// Or
public function setDateDebut(DateTime $dateDebut)
{
$this->dateDebut = clone $dateDebut;
}
You decide where is the most appropriate place to do it, depending how the rest of the code works with these objects.
Because you change the value of $DateDebut in the loop you should make copies of the object there.
If the class Reservation changes the value of its $dateDebut member then you should (also) clone it in the setter method. This is because the caller of Reservation::setDateDebut() does not expect the Reservation class make changes on the value it passes as an argument.

Related

Class-Wide accessible static array, trying to push to it, but keeps coming back empty

class UpcomingEvents {
//Variable I'm trying to make accessible and modify throughout the class methods
private static $postObjArr = array();
private static $postIdArr = array();
private static $pinnedPost;
//My attempt at a get method to solve this issue, it did not
private static function getPostObjArr() {
$postObjArr = static::$postObjArr;
return $postObjArr;
}
private static function sortByDateProp($a, $b) {
$Adate = strtotime(get_field('event_date',$a->ID));
$Bdate = strtotime(get_field('event_date',$b->ID));
if ($Adate == $Bdate) {
return 0;
}
return ($Adate < $Bdate) ? -1 : 1;
}
private static function queryDatesAndSort($args) {
$postQuery = new WP_Query( $args );
if( $postQuery->have_posts() ) {
while( $postQuery->have_posts() ) {
$postQuery->the_post();
//Trying to push to the array, to no avail
array_push(static::getPostObjArr(), get_post());
}
}
//Trying to return the array after pushing to it, comes back empty
return(var_dump(static::getPostObjArr()));
//Trying to sort it
usort(static::getPostObjArr(), array(self,'sortByDateProp'));
foreach (static::getPostObjArr() as $key => $value) {
array_push(static::$postIdArr, $value->ID);
}
}
}
I'm trying to access $postObjArr within the class, and push to it with the queryDatesAndSort(); method. I've tried a couple of things, most recent being to use a get method for the variable. I don't want to make it global as it's bad practice I've heard. I've also tried passing by reference I.E
&static::$postObjArr;
But when it hits the vardump, it spits out an empty array. What would be the solution and best practice here? To allow the class methods to access and modify a single static array variable.
static::$postObjArr[] = get_post()
I didn't think it would of made a difference, but it worked. Can you explain to me why that worked but array.push(); Did not?
Arrays are always copy-on-write in PHP. If you assign an array to another variable, pass it into a function, or return it from a function, it's for all intents and purposes a different, new array. Modifying it does not modify the "original" array. If you want to pass an array around and continue to modify the original array, you'll have to use pass-by-reference everywhere. Meaning you will have to add a & everywhere you assign it to a different variable, pass it into a function, or return it from a function. If you forget your & anywhere, the reference is broken.
Since that's rather annoying to work with, you rarely use references in PHP and you either modify your arrays directly (static::$postObjArr), or you use objects (stdClass or a custom class) instead which can be passed around without breaking reference.

PHP - Editing object clone affects original object

So I have an object, let's call it Example.
class Example {
public function __construct ($id) {
$this->Id = $id;
}
}
$objectA = new Example(10);
It has an id (it pulls this from somewhere), the goal of the object is to overwrite a similar object with this object's properties (post to an external service). This is done by simply changing the ID of the object, and running an ->update() method. However, it must first change its ID (among other properties) to match the ids of object B.
So what I do is clone the current object, reassign the needed properties, and then pass that cloned object to the update method, so that the update method uses the $post values for the update.
public function createPost ($id) {
$post = clone $this;
$post->Id = $id;
return $post;
}
$objectA->update($objectA->createPost(12));
$objectA->update($objectA->createPost(16));
$objectA->update($objectA->createPost(21));
The issue I'm having is this object A needs to be used for multiple different updates, and it uses the ID it is originally assigned as a pointer to what IDs it must later use for $post, and in this scenario, the value of $this->ID is getting reassigned to the $id that is passed in ->setParameters(), even though I'm trying to assign it to a clone of $this, rather than $this itself.
My impression is that $objectA = $objectB assigns ObjectB to the same pointer that points to ObjectA, but that "clone" was supposed to actually make a copy of that object, so that if properties of the clone are changed, the original object remains unaffected, but that doesn't seem to be the case here. Is there a particular method I should instead be using to ensure that the original object's value aren't ever changed when a clone of it is?
I think what you want is a deep clone. Take a look at this link.
The issue I ran into here was a shallow cloning issue it would appear.
Forget what I referenced above, the problem was more so this: -
class Example {
public function __construct ($id) {
$this->ObjId = (object)array("Id" => 5);
$this->Id = $id;
}
}
$example = new Example (5);
$clone = clone $example;
$clone->ObjId->Id = 10;
In this example, I was trying to change the ->Id of a standard php object that was stored within my main object (I had used json_encode to pull a whole structure of objects) that was called "Id". The result of the above was this: -
echo $example->ObjId->Id; //10
echo $example->Id; //5
echo $clone->ObjId->Id; //10
echo $clone->Id; //5
So I had to write this method as part of the Example class: -
public function __clone () {
foreach ($this as $key => $val) {
if (is_object($val) || (is_array($val))) {
$this->{$key} = unserialize(serialize($val));
}
}
}
So now, the result was this: -
echo $example->ObjId->Id; //5
echo $example->Id; //5
echo $clone->ObjId->Id; //10
echo $clone->Id; //5
This is because when I cloned the main Example object, it was creating an new variable for it's properties, but if one of it's properties was an object or array, it was copying the address of that object or array for the new cloned object. The above method prevents that, and does a "deep" copy.

How can I make an array of type "class" in PHP?

I have the following class with several properties and a method in PHP (This is simplified code).
class Member{
public $Name;
public $Family;
public function Fetch_Name(){
for($i=0;$i<10;$i++){
$this[$i]->$Name = I find the name using RegExp and return the value to be stored here;
$this[$i]->Family = I find the family using RegExp and return the value to be stored here;
}
}//function
}//class
In the function Fetch_Name(), I want to find all the names and families that is in a text file using RegExp and store them as properties of object in the form of an array. But I don't know how should I define an array of the Member. Is it logical or I should define StdClass or 2-dimension array instead of class?
I found slightly similar discussion here, but a 2 dimensional array is used instead of storing data in the object using class properties.
I think my problem is in defining the following lines of code.
$Member = new Member();
$Member->Fetch_name();
The member that I have defined is not an array. If I do define it array, still it does not work. I did this
$Member[]= new Member();
But it gives error
Fatal error: Call to a member function Fetch_name() on a non-object in
if I give $Member[0]= new Member() then I don't know how to make $Member1 or Member[2] or so forth in the Fetch_Name function. I hope my question is not complex and illogical.
Many thanks in advance
A Member object represents one member. You're trying to overload it to represent or handle many members, which doesn't really make sense. In the end you'll want to end up with an array that holds many Member instances, not the other way around:
$members = array();
for (...) {
$members[] = new Member($name, $family);
}
Most likely you don't really need your Member class to do anything really; the extraction logic should reside outside of the Member class, perhaps in an Extractor class or something similar. From the outside, your code should likely look like this:
$parser = new TextFileParser('my_file.txt');
$members = $parser->extractMembers();
I think you should have two classes :
The first one, Fetcher (or call it as you like), with your function.
The second one, Member, with the properties Name and Family.
It is not the job of a Member to fetch in your text, that's why I would make another class.
In your function, do your job, and in the loop, do this :
for($i = 0; $i < 10; ++$i){
$member = new Member();
$member->setName($name);
$member->setFamily($family);
// The following is an example, do what you want with the generated Member
$this->members[$i] = $member;
}
The problem here is that you are not using the object of type Member as array correctly. The correct format of your code would be:
class Member{
public $Name;
public $Family;
public function Fetch_Name(){
for($i=0;$i<10;$i++){
$this->Name[$i] = 'I find the name using RegExp and return the value to be stored here';
$this->Family[$i] = 'I find the family using RegExp and return the value to be stored here';
}
}
}
First, $this->Name not $this->$Name because Name is already declared as a member variable and $this->Name[$i] is the correct syntax because $this reference to the current object, it cannot be converted to array, as itself. The array must be contained in the member variable.
L.E: I might add that You are not writing your code according to PHP naming standards. This does not affect your functionality, but it is good practice to write your code in the standard way. After all, there is a purpose of having a standard.
Here you have a guide on how to do that.
And I would write your code like this:
class Member{
public $name;
public $family;
public function fetchName(){
for($i=0;$i<10;$i++){
$this->name[$i] = 'I find the name using RegExp and return the value to be stored here';
$this->family[$i] = 'I find the family using RegExp and return the value to be stored here';
}
}
}
L.E2: Seeing what you comented above, I will modify my answer like this:
So you are saying that you have an object of which values must be stored into an array, after the call. Well, after is the key word here:
Initialize your object var:
$member = new Memeber();
$memebr->fechNames();
Initialize and array in foreach
$Member = new Member();
foreach ($Member->Name as $member_name){
$array['names'][] = $member_name;
}
foreach ($Member->Family as $member_family) {
$array['family'][] = $member_family;
}
var_dump($array);
Is this more of what you wanted?
Hope it helps!
Keep on coding!
Ares.

PHP combine $this variable

How to combine two variables to obtain / create new variable?
public $show_diary = 'my';
private my_diary(){
return 1;
}
public view_diary(){
return ${"this->"}.$this->show_diary.{"_diary()"}; // 1
return $this->.{"$this->show_diary"}._diary() // 2
}
both return nothing.
Your class should be like following:
class Test
{
public $show_diary;
function __construct()
{
$this->show_diary = "my";
}
private function my_diary(){
return 707;
}
public function view_diary(){
echo $this->{$this->show_diary."_diary"}(); // 707
}
}
It almost looks from your question like you are asking about how to turn simple variables into objects and then how to have one object contain another one. I could be way off, but I hope not:
So, first off, what is the differnce between an object and a simple variable? An object is really a collection of (generally) at least one property, which is sort of like a variable within it, and very often functions which do things to the properties of the object. Basically an object is like a complex variable.
In PHP, we need to first declare the strucutre of the object, this is done via a class statement, where we basicaly put the skeleton of what the object will be into place. This is done by the class statement. However, at this point, it hasn't actually been created, it is just like a plan for it when it is created later.
The creation is done via a command like:
$someVariable= new diary();
This executes so create a new variable, and lays it out with the structure, properties and functions defined in the class statement.
From then on, you can access various properties or call functions within it.
class show_diary
{
public $owner;
public function __construct()
{
$this->owner='My';
}
}
class view_diary
{
public $owner;
public $foo;
public function __construct()
{
$this->foo='bar';
$this->owner=new show_diary();
}
}
$diary= new view_diary();
print_r($diary);
The code gives us two classes. One of the classes has an instance of the other class within it.
I have used constructors, which are a special type of function that is executed each time we create a new instance of a class - basically each time we declare a variable of that type, the __construct function is called.
When the $diary= new view_diary(); code is called, it creates an instance of the view_diary class, and in doing so, the first thing it does is assigns it's own foo property to have the value 'bar' in it. Then, it sets it's owner property to be an instance of show_diary which in turn then kicks off the __construct function within the new instance. That in turn assigns the owner property of the child item to have the value 'My'.
If you want to access single properties of the object, you can do so by the following syntax:
echo $diary->foo;
To access a property of an object inside the object, you simply add more arrows:
echo $diary->owner->owner;
Like this?
$diary = $this->show_diary . '_diary';
return $this->$diary();

PHP custom object casting

I have a custom class object in PHP named product:
final class product
{
public $id;
public $Name;
public $ProductType;
public $Category;
public $Description;
public $ProductCode;
}
When passing an object of this class to my Data Access Layer I need to cast the object passed into a type of the product class so I can speak to the properties within that function. Since type casting in PHP works only with basic types what is the best solution to cast that passed object?
final class productDAL
{
public function GetItem($id)
{
$mySqlConnection = mysql_connect('localhost', 'username', 'password');
if (!$mySqlConnection) { trigger_error('Cannot connect to MySql Server!'); return; }
mysql_select_db('databaseName');
$rs = mysql_query("SELECT * FROM tblproduct WHERE ID='$id';");
$returnObject = mysql_fetch_object($rs, 'product');
return $returnObject;
}
public function SaveItem($objectToSave, $newProduct = false)
{
$productObject = new product();
$productObject = $objectToSave;
echo($objectToSave->Name);
$objectToSave->ID;
}
}
Right now I am creating a new object cast as a type of product and then setting it equal to the object passed to the function. Is there a better way of accomplishing this task? Am I going about the wrong way?
EDITED FOR CLARITY - ADD FULL PRODCUTDAL CLASS
You don't need to cast the object, you can just use it as if it was a product.
$name = $objectToSave->Name;
I´m not sure what you are trying to achieve, but if $objectToSave is already of class product:
You can simply call $objectToSave->SaveItem() (assuming SaveItem() is part of the product class) and access it´s properties in the function like $this->Name, etc.;
In your code $productObject and $objectToSave will hold a reference to the same object.
Type casts in PHP are done like this:
$converted = (type) $from;
Note, that this won't work if the object types are not compatible (if for example $form happens to be a string or object of mismatching type).
But usual solution (called Active Record pattern, present for example in Zend Framework) is to have a base class for a database item called Row. Individual items (for example the class product from your sample) then inherit from this class.
Typical ZF scenario:
$table = new Product_Table();
$product = $table->find($productId); // load the product with $productId from DB
$product->someProperty = $newPropertyValue;
$product->Save(); // UPDATE the database
Which is IMO much better than your solution.
EDIT:
You can't cast between two unrelated objects, it is not possible.
If you want to use the DAL like this, skip the "product" object and go for simple associative array. You can enumerate over its members with foreach, unlike object's properties (you could use reflection, but that's overkill).
My recommendation: Go for the Active Record pattern (it is easy to implement with magic methods). It will save you a lot of trouble.
Currently, you are creating a new Product, then discarding it immediately (as its reference is replaced by $objectToSave.) You will need to copy its properties one by one, I regret.
foreach (get_object_vars($objectToSave) as $key => $value)
{
$product->$key = $value;
}
(If the properties of $objectToSave are private, you will need to a expose a method to_array() that calls get_object_vars($this).)

Categories