I´m trying to learn construct and destruct.
So, I made this
<?php
class Numbers {
public function __construct($numberint,$numbername,$numberletter,$numberpos) {
$this->numberint = $numberint;
$this->numbername = $numbername;
$this->numberletter = $numberletter;
$this->numberpos = $numberpos;
}
public function __destruct() {
unset($this->numberpos);
}
}
$number1 = new Numbers(1,"One","A",0);
print_r($number1);
?>
As you can see, I create the class Number and then, use construct for the Objects. But after construct, I want to use destruct, in this case, unset numberpos. I´m trying to put them together to understand how the work.
Anyone can help me?
My idea is to change the result:
Numbers Object ( [numberint] => 1 [numbername] => One [numberletter] => A [numberpos] => 0 )
To...
Numbers Object ( [numberint] => 1 [numbername] => One [numberletter] => A )
Thanks and remember that I´m learning :D
The destructor is there to destroy the whole object, not parts of an object. If you want your desired output, you could just do:
$number1 = new Numbers(1,"One","A",0);
print_r($number1);
unset($number1->numberpos);
print_r($number1);
Demo.
If you want to see your destructor getting called, unset the object:
class Numbers {
public function __destruct() {
echo "Destructing!\n";
}
}
$number1 = new Numbers();
unset($number1);
echo "Done!";
Outputs:
Destructing!
Done!
Related
I am trying to convert my string on id's into variable names and inject them into my function.
I have a json object with the following information in it:
Object
(
[files] => file1.php,fie2.php
[dependencies] => db,templates
[classname] => SomeClass
)
I am able to loop through everything and get it to work with a single variable name, but when there is more than one dependency, I need to loop through them, make them variables, and then pass to a function depending on how many are needed dynamically from this object above.
// First I make sure the dependency object exists, this one has 'db,templates' in it
if (!empty($json_data->dependencies)) {
// I explode them into an array, to see if there is more than one
$dependence_string = explode(",", $json_data->dependencies);
if (is_array($dependence_string)) {
// I make a dummy variable
$dependencies = NULL;
foreach ($dependence_string as $dependency) {
$dependencies[] = '$' . $dependency;
}
// Now i have an array with two values "$db", "$templates"
// This gets inserted as new SomeClass(Array()); but I need to
// somehow be able to convert it to new SomeClass($db, $templates);
$some_value = new $json_data->classname($dependencies);
} else {
// This is easy to handle and is done already
}
Now i have an array with two values "$db", "$templates" and this gets inserted as new SomeClass(Array()); but I need to somehow be able to convert it to new SomeClass($db, $templates); and keep them comma separated as variables from their string names.
What method would I use for this? I tried implode but it still sends as a string and I need to convert it to individual items and send however many the current script needs to run.
Got it to work with the following code:
foreach ($dependence_string as $dependency) {
$dependencies[] = '$' . $dependency;
}
$some_value = (new ReflectionClass($json_data->classname))->newInstanceArgs($dependencies);
The splat operator could be the solution to your issue.
<?php
declare(strict_types=1);
namespace Marcel;
class SomeClass
{
protected string $db;
protected string $templates;
public function __construct(string $db, string $templates)
{
$this->db = $db;
$this->templates = $templates;
}
}
foreach ($dependence_string as $dependency) {
$dependencies[] = '$' . $dependency;
}
$class = new SomeClass(...$dependencies);
Type hinting is not required but would be nice. To keep the example simple, strings are used here.
I wrote some program to check the value in an array.
var_dump($profileuser);//NULL
$profileuser = get_user_to_edit($user_id);//fetch the value of $profileuser
var_dump($profileuser);//does not print the value of $profileuser->user_url
//nor by print_r($profileuser)
if(isset($profileuser->user_url))
echo $profileuser->user_url;//printed!!!!How is it possible??
Could somebody can explain how this happened?
background:
I modified the kernel of wordpress.
This happened when I modified the file of wp-admin/user-edit.php.
You say it's an array, but you're accessing it as an object ($obj->foo rather than $arr['foo']), so it's most likely an object (actually it is - get_user_to_edit returns a WP_User). It could easily contain the magic __get and __isset methods that would lead to this behaviour:
<?php
class User {
public $id = 'foo';
public function __get($var) {
if ($var === 'user_url') {
return 'I am right here!';
}
}
public function __isset($var) {
if ($var === 'user_url') {
return true;
}
return false;
}
}
$user = new User();
print_r($user);
/*
User Object
(
[id] => foo
)
*/
var_dump( isset($user->user_url) ); // bool(true)
var_dump( $user->user_url ); // string(16) "I am right here!"
DEMO
One possibility is that $profileuser is an Object that behaves as an array and not an array itself.
This is possible with interface ArrayAccess. In this case, isset() would return true and you might not see it when you do var_dump($profileuser);.
When you want an object to behave like an array, you need to implement some methods which tell your object what to do when people use it as if it were an array. In that case, you could even create an Object that, when accessed as an array, fetches some webservice and return the value. That may be why you are not seeing those values when you var_dump your variable.
I thinks it's not possible, I've created test code and var_dump behaves correctly. Are you 100% sure you don't have any typo in your code? I remind variables in PHP are case sensitive
<?php
$profileuser = null;
class User
{
public $user_url;
}
function get_user_to_edit($id) {
$x = new User();
$x->user_url = 'vcv';
return $x;
}
var_dump($profileuser);//NULL
$user_id = 10;
$profileuser = get_user_to_edit($user_id);//fetch the value of $profileuser
var_dump($profileuser);//does not print the value of $profileuser->user_url
//nor by print_r($profileuser)
if(isset($profileuser->user_url))
echo $profileuser->user_url;//printed!!!!How does it possible??
Result is:
null
object(User)[1]
public 'user_url' => string 'vcv' (length=3)
vcv
I'm experimenting with OOP and PHP.
I don't know why I would ever need to do something like this but I'm wondering how it would be done and cant find it online.
class Example{
public $a = 'aye';
public $b = 'bee';
public $c = 'see';
public function how(){
return (object)array(
$this->a,
$this->b,
$this->c
);
}
}
$example = new Example;
$how = $example->how();
echo $how->1; //I thought would print bee
I'm aware that giving the array keys would let me do
echo $how->beekey //which would give me beekey's value
This is basically not possible, as explained in this bug report; numeric object properties are kind of a gray area in PHP.
However, you can cast the object back to an array and reference the value:
$arr = (array)$how;
echo $arr[1];
Or, use as a one-liner:
echo current(array_slice((array)$how, 1, 1));
The best advice I could give you is to not turn it into an object in the first place:
public function how()
{
return array(
$this->a,
$this->b,
$this->c
);
}
And then just reference it as $how[1].
Btw, $how->{1} used to work in PHP 4 :)
What about using a loop?
foreach($how as $value)
{
echo $value .'<br>'; //this print your values: aye<br>bee<br>see
}
I have an Object that needs to access a previously declared array in my statistics. I can of course create the entire array inside of the object, but since multiple objects use the exact same array there is no reason to clog up memory or time by making a call to the Database to create the same array every time I create a new object.
So, I understood that Objects cannot access global variables, but is there any work-around to access an external Array from within the object?
example Code:
global $stats = array();
$stats[1]['value']= 10;
$stats[1]['value1'] =2;
$stats[2]['value']= 12;
$stats[2]['value1'] =1;
class Obj() {
private $valueA;
private $valueB;
function __construct($user) {
//access Database lets call $SQL;
$valueA = SQL->value;
}
function showA() {
return ( $valueA * $stats[1]['value1']) + $stats[1]['value'];
}
}
Yes how about changing your class to look like this:
class Obj() {
private $valueA;
private $valueB;
private $stats;
function __construct($user, $stats) {
$this->stats = $stats;
//access Database lets call $SQL;
$valueA = SQL->value * $this->stats[1]['value1'] + $this->stats[1]['value'];
$valueB = SQL->value * $this->stats[2]['value1'] + $this->stats[2]['value'];
}
function showA() {
return $valueA;
}
}
You than just pass $stats to the object at instantiation. Or if you don't want it in the constructor, just make a setStats($stats) method that does the same.
I'll tell you three ways to do this:
pass the array into the constructor of the class. e.g.: $myObject =
new Obj( $stats );
make a class that serves up the $stats array: $stats = new Stats(); $statsArray = $stats->getStats();
use the term global inside of a public method in your class itself (not construct) to get that variable: 3:
function() somePublicMethod() {
global $stats;
$valueA = SQL->value * $stats[1]['value1'] + $stats[1]['value'];
$valueB = SQL->value * $stats[2]['value1'] + $stats[2]['value'];
}
You can access variables from within a class, i.e.
$stats[1]['value']= 10;
$stats[1]['value1'] =2;
$stats[2]['value']= 12;
$stats[2]['value1'] =1;
class Obj {
var $myStats;
function __construct() {
global $stats;
$this->myStats= $stats;
print_r($this->myStats);
}
}
$obj=new Obj; // Array ( [1] => Array ( [value] => 10 [value1] => 2 ) [2] => Array ( [value] => 12 [value1] => 1 ) )
DEMO.
Thanks to Mike, Sheikh and Kristian,
I can't in all Faith give a tick to your answers, because your words did not help me to understand the answer, Putting 'global $stats;' into the class results in an Error which I pointed out in my responses. but I will 'up' your scores when I permission from the site to do so.
For anyone looking for the answer to this, a Reminder, the key point is not to store the entire Array in the class, creating a huge waste of memory. The Key point is to gain access to the Variable which exists outside of the class.
While adding access to the global $stats by including it in the functions of the class, does produce the required results, It still requires that the Data is being stored in the class, which is again, against the point. Sorry I wasn't clear on this from the very beginning.
Instead:
example Code:
function showA(&$stats) {
return ( $valueA * $stats[1]['value1']) + $stats[1]['value'];
}
}
This, if I understand correctly, will use the pointer to the $stats variable, only within the scope of returning the $valueA after it has been modified using the stats array. not copying the entire array into another memory location, nor the class.
So, I have a object with structure similar to below, all of which are returned to me as stdClass objects
$person->contact->phone;
$person->contact->email;
$person->contact->address->line_1;
$person->contact->address->line_2;
$person->dob->day;
$person->dob->month;
$person->dob->year;
$album->name;
$album->image->height;
$album->image->width;
$album->artist->name;
$album->artist->id;
etc... (note these examples are not linked together).
Is it possible to use variable variables to call contact->phone as a direct property of $person?
For example:
$property = 'contact->phone';
echo $person->$property;
This will not work as is and throws a E_NOTICE so I am trying to work out an alternative method to achieve this.
Any ideas?
In response to answers relating to proxy methods:
And I would except this object is from a library and am using it to populate a new object with an array map as follows:
array(
'contactPhone' => 'contact->phone',
'contactEmail' => 'contact->email'
);
and then foreaching through the map to populate the new object. I guess I could envole the mapper instead...
If i was you I would create a simple method ->property(); that returns $this->contact->phone
Is it possible to use variable variables to call contact->phone as a direct property of $person?
It's not possible to use expressions as variable variable names.
But you can always cheat:
class xyz {
function __get($name) {
if (strpos($name, "->")) {
foreach (explode("->", $name) as $name) {
$var = isset($var) ? $var->$name : $this->$name;
}
return $var;
}
else return $this->$name;
}
}
try this code
$property = $contact->phone;
echo $person->$property;
I think this is a bad thing to to as it leads to unreadable code is is plain wrong on other levels too, but in general if you need to include variables in the object syntax you should wrap it in braces so that it gets parsed first.
For example:
$property = 'contact->phone';
echo $person->{$property};
The same applies if you need to access an object that has disalowed characters in the name which can happen with SimpleXML objects regularly.
$xml->{a-disallowed-field}
If it is legal it does not mean it is also moral. And this is the main issue with PHP, yes, you can do almost whatever you can think of, but that does not make it right. Take a look at the law of demeter:
Law of Demeter
try this if you really really want to:
json_decode(json_encode($person),true);
you will be able to parse it as an array not an object but it does your job for the getting not for the setting.
EDIT:
class Adapter {
public static function adapt($data,$type) {
$vars = get_class_vars($type);
if(class_exists($type)) {
$adaptedData = new $type();
} else {
print_R($data);
throw new Exception("Class ".$type." does not exist for data ".$data);
}
$vars = array_keys($vars);
foreach($vars as $v) {
if($v) {
if(is_object($data->$v)) {
// I store the $type inside the object
$adaptedData->$v = Adapter::adapt($data->$v,$data->$v->type);
} else {
$adaptedData->$v = $data->$v;
}
}
}
return $adaptedData;
}
}
OOP is much about shielding the object's internals from the outside world. What you try to do here is provide a way to publicize the innards of the phone through the person interface. That's not nice.
If you want a convenient way to get "all" the properties, you may want to write an explicit set of convenience functions for that, maybe wrapped in another class if you like. That way you can evolve the supported utilities without having to touch (and possibly break) the core data structures:
class conv {
static function phone( $person ) {
return $person->contact->phone;
}
}
// imagine getting a Person from db
$person = getpersonfromDB();
print conv::phone( $p );
If ever you need a more specialized function, you add it to the utilities. This is imho the nices solution: separate the convenience from the core to decrease complexity, and increase maintainability/understandability.
Another way is to 'extend' the Person class with conveniences, built around the core class' innards:
class ConvPerson extends Person {
function __construct( $person ) {
Person::__construct( $person->contact, $person->name, ... );
}
function phone() { return $this->contact->phone; }
}
// imagine getting a Person from db
$person = getpersonfromDB();
$p=new ConvPerson( $person );
print $p->phone();
You could use type casting to change the object to an array.
$person = (array) $person;
echo $person['contact']['phone'];
In most cases where you have nested internal objects, it might be a good time to re-evaluate your data structures.
In the example above, person has contact and dob. The contact also contains address. Trying to access the data from the uppermost level is not uncommon when writing complex database applications. However, you might find your the best solution to this is to consolidate data up into the person class instead of trying to essentially "mine" into the internal objects.
As much as I hate saying it, you could do an eval :
foreach ($properties as $property) {
echo eval("return \$person->$property;");
}
Besides making function getPhone(){return $this->contact->phone;} you could make a magic method that would look through internal objects for requested field. Do remember that magic methods are somewhat slow though.
class Person {
private $fields = array();
//...
public function __get($name) {
if (empty($this->fields)) {
$this->fields = get_class_vars(__CLASS__);
}
//Cycle through properties and see if one of them contains requested field:
foreach ($this->fields as $propName => $default) {
if (is_object($this->$propName) && isset($this->$propName->$name)) {
return $this->$propName->$name;
}
}
return NULL;
//Or any other error handling
}
}
I have decided to scrap this whole approach and go with a more long-winded but cleaner and most probably more efficient. I wasn't too keen on this idea in the first place, and the majority has spoken on here to make my mind up for me. Thank for you for your answers.
Edit:
If you are interested:
public function __construct($data)
{
$this->_raw = $data;
}
public function getContactPhone()
{
return $this->contact->phone;
}
public function __get($name)
{
if (isset($this->$name)) {
return $this->$name;
}
if (isset($this->_raw->$name)) {
return $this->_raw->$name;
}
return null;
}
In case you use your object in a struct-like way, you can model a 'path' to the requested node explicitly. You can then 'decorate' your objects with the same retrieval code.
An example of 'retrieval only' decoration code:
function retrieve( $obj, $path ) {
$element=$obj;
foreach( $path as $step ) {
$element=$element[$step];
}
return $element;
}
function decorate( $decos, &$object ) {
foreach( $decos as $name=>$path ) {
$object[$name]=retrieve($object,$path);
}
}
$o=array(
"id"=>array("name"=>"Ben","surname"=>"Taylor"),
"contact"=>array( "phone"=>"0101010" )
);
$decorations=array(
"phone"=>array("contact","phone"),
"name"=>array("id","name")
);
// this is where the action is
decorate( $decorations, &$o);
print $o->name;
print $o->phone;
(find it on codepad)
If you know the two function's names, could you do this? (not tested)
$a = [
'contactPhone' => 'contact->phone',
'contactEmail' => 'contact->email'
];
foreach ($a as $name => $chain) {
$std = new stdClass();
list($f1, $f2) = explode('->', $chain);
echo $std->{$f1}()->{$f2}(); // This works
}
If it's not always two functions, you could hack it more to make it work. Point is, you can call chained functions using variable variables, as long as you use the bracket format.
Simplest and cleanest way I know of.
function getValueByPath($obj,$path) {
return eval('return $obj->'.$path.';');
}
Usage
echo getValueByPath($person,'contact->email');
// Returns the value of that object path