I have a class called contact:
class contacts
{
public $ID;
public $Name;
public $Email;
public $PhoneNumber;
public $CellPhone;
public $IsDealer;
public $DealerID;
}
At some point in my code I would like to point to a property within that class and return the name of the property.
<input type="text"
id="<?php key($objContact->Name)" ?>"
name="<?php key($objContact->Name)" ?>"
value="<?php $_POST['contact'.key($objContact->Name)]" />
My issue being that the key() function only deals with arrays or objects. $objContact->Name itself does not meet these requirements. I know it would be just as simple to type the name itself out into the ID and NAME fields but this is for other code verification uses. Imagine the processor page:
$objContact = new contact();
$objContact->Email = $_POST[$objContact->Email->**GetSinglePropertyName()**];
$objContact->PhoneNumber = $_POST[$objContact->PhoneNumber->**GetSinglePropertyName()**];
This allows me to turn on STRICT and ensure that as I'm writing I'm not creating any fat finger errors along the way that are going to have me denting my head anymore than it presently exist.
UPDATE WITH ANSWER
Answer provided by: linepogl
Now I've taken linepogl's idea and extended is some so it can work very easily with my existing code base. Here's what I've come up with:
class baseData {
public $meta;
public function __construct() {
$this->meta = new Meta($this);
}
}
class Meta {
public function __construct($obj) {
$a = get_object_vars($obj);
foreach ($a as $key => $value){
$this->$key = $key;
}
}
}
class contacts extends baseData
{
public $ID;
public $Name;
public $Email;
public $PhoneNumber;
public $CellPhone;
public $IsDealer;
public $DealerID;
}
Which means I can now call the following code with the desired results:
$objContact = new contacts();
echo($objContact->meta->Email);
So, you want when you type $objContact->Name to take as an answer not the evaluation of this expression but its meta data, which in this case is a ReflectionProperty object.
What you want is a feature that is called metaprogramming ( http://en.wikipedia.org/wiki/Metaprogramming ). Of course php does not support that but there are other languages that do, such as Lisp etc. Rumors say that C# 5.0 will introduce such features.
You can achieve a similar effect by using Reflection ( http://php.net/manual/en/book.reflection.php ). You can get the meta-object of $objContact (ReflectionClass) and iterate over the properties.
So, there is no way to identify a specific property with an identifier. The only way to do is is with a string of its name.
EDIT:
Yet, there a way to simulate it! Write a class like this:
class Meta {
public function __construct($obj) {
$a = get_object_vars($obj);
foreach ($a as $key => $value){
$this->$key = $key; // <-- this can be enhanced to store an
// object with a whole bunch of meta-data,
// but you get the idea.
}
}
}
So now you will be able to do this:
$meta = new Meta($objContact);
echo $meta->Name; // <-- with will return 'Name'!
You can use get_object_vars() like this:
$properties = get_object_vars($objContact);
foreach($properties as $name => $value)
{
if($value == $objContact->Name)
{
//here's youre name
}
}
but with this you will have to assume that $objContact->Name has unique value over all properties...
The key() function works very well with objects. It just doesn't accomplish what you are seemingly trying to do.
$c = new contacts;
end($c);
print key($c); // "DealerID"
You can foreach over object attributes, and PHP remembers the last accessed key(). But I'm not sure if this is what you want.
As alluded to by konforce, is this what you are looking for?
$var = 'Name';
$Obj->$var;//Obj's Name property
...
id="<?php $var ?>" //id="Name"
...
$_POST['contact'.$var];//$_POST['contactName']
Related
I am in learning phase of OOP and PHP. Below is how i implemented __get method. It is working fine but i don't understand why to use it. Since in my example i set the property to protected deliberately so that i can't be accessed via outside class. Then what is the purpose of __get then ?
class Magic {
protected $name = 'John';
public $age = 26;
public $new_name;
public function __get($key){
$this->new_name = $key;
}
public function get_new_name(){
return $this->new_name. " is my friend";
}
}
$person = new Magic();
$person->Alan;
echo $person->get_new_name();
There is no valid reason I would have thought of that you would use __get() with a protected string, protected arrays would be useful, but not strings. The example you provided works, but it isn't going to be the best code for others to understand or for use with IDEs (code editors).
Since you don't seem to understand what I was saying, here is an example of a quick database script.
Let's say you want to insert a row in the database using an ORM-like class. You would do something like:
Class Person {
protected $fields = array();
public function setField($name, $value) {
$this->fields[$name] = $value;
}
public function getField($name) {
return $this->fields[$name];
}
public function save() {
Database::insert($table, $fields); // Generic function to insert the row, don't worry about this.
}
}
Now in this instance you could do:
$person = new Person();
$person->setField('name', 'Bob');
$person->setField('age', '30');
$person->save();
echo $person->getField('name'); // Echoes Bob
Overloading
Now to change this, we could use overloading with __set() instead of setField() and __get() instead of getField():
Class Person {
protected $fields = array();
public function __set($name, $value) {
$this->fields[$name] = $value;
}
public function __get($name) {
return $this->fields[$name];
}
public function save() {
Database::insert($table, $fields);
}
}
Now in this instance you could do:
$person = new Person();
$person->name = 'Bob';
$person->age = '30';
$person->save();
echo $person->name; // Echoes Bob
Hopefully this gives you an easy example of how overloading can work. We don't want to declare the properties $name and $age because we want to use those properties to build the $fields array which is later used in the insert.
For example you can use the __get method for obtain the value of an array. In this case you can have a dynamic number of class variable.
public function __get($key){
return $this->property[$key];
}
I am following a tutorial and have come across the following code in defining a user class:
class User {
public $id;
public $username;
public $password;
public $first_name;
public $last_name;
public static function instantiate($record) {
$object = new self;
foreach ($record as $attribute => $value){
if ($object->has_attribute($attribute)){
$object->$attribute = $value;
}
}
return $object;
}
private function has_attribute($attribute) {
$object_vars = get_object_vars($this);
return array_key_exists($attribute, $object_vars);
}
}
My question is: What does the "$object->$attribute = $value;" do exactly ?
I am just starting in OOP php and I am really confuse of what that bit of code is downing.
Thanks a lot.
Pretty basic question : it is assigning the value $value to the attribute $attribute of the object $object.
In other words, it is copying the value of the variable $value to the attribute of the object $object.
It's an assignment statement for an attribute of the PHP class. Let's use a less ambiguous example. We will create a small person class that holds a first name and a last name.
class Person
{
//Class attributes
public $fisrtName;
public $lastName;
}
Using the above example, if you wanted to set those attributes, you would do the following:
//Instantiate a new person
$myPerson = new Person();
//Assign values to the person object
$myPerson->firstName = "John";
$myPerson->lastName = "Smith";
Alternately, if you wanted to assign the value myPerson object's firstName field to a different variable, you could do the following:
$personsName = $myPerson->firstName;
All this is doing is internally creating a new instance of it's creating a new instance of it's self for a form of recursion or other functionality,
so calling:
$object->$attribute
is essentially, from what I can see. Will create a new instance then depending on the contents of $attribute return a value or call a method
I've read that you can make all your access through a single section of code using accessor function. The book shows me the code, I got it.
But I don't know how to use it. Can someone give me an example or a syntax to use this function please?
The code from my book:
class classname
{
public $attribute;
function __get($name)
{
return $this->$name;
}
function __set($name, $value)
{
$this->$name = $value;
}
}
Accessors provide a way to access private class variables.
An example(let's just say that $attribute is private):
<?php
$classNameObject = new classname();
// Setting the value
$classNameObject->attribute = "A value";
// Getting the value
echo $classNameObject->attribute;
?>
But in php the __set() and __get() functions work in a way that they can create dynamic properties.
I came from Java world and try the same "easy" things in Php.
I have a immutable dummy data object:
class BugTimeData {
private $bugid = "";
private $startDate = "";
private $resolvedDate = "";
private $status = "";
private $weekends = "";
function __construct($bugid, $startDate, $resolvedDate, $status) {
$this->bugid = $bugid;
$this->startDate = $startDate;
$this->resolvedDate = $resolvedDate;
$this->status = $status;
}
function getBugId() {
return $this->bugid;
}
function getStartDate() {
return $this->startDate;
}
function getResolvedDate() {
return $this->resolvedDate;
}
function getStatus() {
return $this->status;
}
function getWeekendsBetween() {
return $this->weekends;
}
}
A add a object from this class into an array:
$data= new BugTimeData($a, $b, $c, $d);
array_push($content, $data);
I want to iterate over this array, read out objects and access their methods:
foreach($time_prio_bug_content as $key => $value) {
var_dump($value->getStatus());
}
This works! But my IDE (Eclipse) does not really know that $value is from type BugTimeData. So I cannot access public methods in a easy way.
Question:
How to cast $value to a object from type BugTimeData?
In Java this is really easy (because I do not need a cast because I can define the type of the objects when creating an array) and straight forward. So I wonder why this is not possible in Php?
It's just a problem of your IDE, not of PHP. If you add the appropriate annotation type hints, any decent IDE will pick up on it. For instance, define that the array contains objects of a certain type:
/** #var BugTimeData[] $array */
$array = array();
If the data comes from a function or method, add an appropriate #return documentation tag to the method's signature. Worst case, mark the variable inside the loop:
foreach($time_prio_bug_content as $key => $value) {
/** #var BugTimeData $value */
var_dump($value->getStatus());
}
As an alternative to Annotation I believe you can type hint as such:
var $value = new BugTimeData; // this tells the IDE which type the variable will hold from here on
foreach($time_prio_bug_content as $key => $value) {
var_dump($value->getStatus());
}
or implement a class method for the cast with type hinting the argument and return object (see link)
You can't. Because PHP is practically typeless, and when reading code there's no way to know what type a certain variable is. It is only possible during runtime.
This thread didn't helped me.
If I use
$class_vars = get_class_vars(get_class($this));
foreach ($class_vars as $name => $value) {
echo "$name : $value\n";
}
I get
attrib1_name : attrib2_name : attrib3_name
There are no values. Also a private attribute is shown, which I don't want.
If I use
echo "<pre>";
print_r(get_object_vars($this));
echo "</pre>";
I get
Array
(
[atrrib1_name] => attrib1_value
[attrib2_name] => attrib2_value
)
Here again I have a private attribute and all sub attributes. But this time I have the values. How can I constrain this to one level?
Isn't there a possibility to show all public attributes with their values of an object?
You are seeing non-public properties because get_class_vars works according to current scope. Since you are using $this your code is inside the class, so the non-public properties are accessible from the current scope. The same goes for get_object_vars which is probably a better choice here.
In any case, a good solution would be to move the code that retrieves the property values out of the class.
If you do not want to create a free function for that (why? seriously, reconsider!), you can use a trick that involves an anonymous function:
$getter = function($obj) { return get_object_vars($obj); };
$class_vars = $getter($this);
See it in action.
Update: Since you are in PHP < 5.3.0, you can use this equivalent code:
$getter = create_function('$obj', 'return get_object_vars($obj);');
$class_vars = $getter($this);
You can do this easily with php Reflection api
Extending Mr.Coder's answer, here is a snippet to fetch the public attributes of the object (name and value) as an array
public function getPublicProperties()
{
$results = [];
$reflectionObject = (new ReflectionObject($this));
$properties = $reflectionObject->getProperties(ReflectionProperty::IS_PUBLIC);
foreach ($properties as $property) {
$results[$property->getName()] = $property->getValue($this);
}
return $results;
}
Use get_object_vars.
see: http://dk.php.net/manual/en/function.get-object-vars.php
I Fully recognize what you are trying to achieve so why not have something external like this to help out... (pasted from PHPFiddle)
<?php
final class utils {
public static function getProperties(& $what) {
return get_object_vars($what);
}
}
class ball {
var $name;
private $x, $y;
function __construct($name,$x,$y) {
}
function publicPropsToArray() {
return utils::getProperties($this);
}
function allPropsToArray() {
return get_object_vars($this);
}
}
$ball1 = new ball('henry',5,6);
//$ball2 = new ball('henry',3,4);
echo "<pre>";
print_r($ball1->publicPropsToArray());
echo "\r\n\r\n";
print_r($ball1->allPropsToArray());
echo "\r\n\r\n";
?>
This way I can both access all properties of the object or for something such as a database access layer or similarly for a function that send "safe" data to a view or another un-privileged model I can send just the public properties, but have the behaviour defined within the object.
Sure this leads to coupling with a utility class, but to be fair not all couplings are bad, some are nesecarry to achieve an end goal, dont get bogged down by these things