Is there such a function like in_array, but can be used on objects?
Nope, but you can cast the object to an array and pass it into in_array().
$obj = new stdClass;
$obj->one = 1;
var_dump(in_array(1, (array) $obj)); // bool(true)
That violates all kinds of OOP principles though. See my comment on your question and Aron's answer.
First of all, arrays and objects are quite different.
A PHP object can not be iterated through like an array, by default. A way to implement object iteration is to implement the Iterator interface.
Concerning your specific question, you probably want to take a look at the ArrayAccess interface:
class obj implements ArrayAccess {
private $container = array();
public function __construct() {
$this->container = array(
"one" => 1,
"two" => 2,
"three" => 3,
);
}
public function offsetSet($offset, $value) {
if (is_null($offset)) {
$this->container[] = $value;
} else {
$this->container[$offset] = $value;
}
}
public function offsetExists($offset) {
return isset($this->container[$offset]);
}
public function offsetUnset($offset) {
unset($this->container[$offset]);
}
public function offsetGet($offset) {
return isset($this->container[$offset]) ? $this->container[$offset] : null;
}
}
Now you can access your object like an array in the following manner:
$object = new obj();
var_dump(isset($obj['two'])); // exists!
var_dump(isset($obj['foo'])); // does not exist
Before you go crazy on this though, please consider why you are actually trying to do this and take a look at the examples at php.net.
Option 2: when you are simply trying to see if a property exists, you can use property_exists() for this:
class foo {
public $bar = 'baz';
}
$object = new foo();
var_dump(property_exists($object, 'bar')); // true
You could cast the object to an array:
$obj = new stdClass();
$obj->var = 'foobar';
in_array( 'foobar', (array)$obj ); // true
function in_object($needle, $haystack) {
return in_array($needle, get_object_vars($haystack));
}
It's unbelievable how all the people miss the point of the usefulness of an in_object PHP method! Here is what I came up with, it is very useful, and you will see why!
Here is a simple function I wrote which will check if a value can be found within an object.
<?php
// in_object method
// to check if a value in an object exists.
function in_object($value,$object) {
if (is_object($object)) {
foreach($object as $key => $item) {
if ($value==$item) return $key;
}
}
return false;
}
?>
This is very useful if an object has been created dynamically (especially from external code, which you don't control, as in an application-plugin, CMS, etc), and you don't know the object's properties.
The above function will return the property, so you will be able to use it in your code later on.
Here is a very good basic example of how useful this function is!
<?php
class My_Class {
function __construct($key, $value) {
$this->$key = $value;
// As you can see, this is a dynamic class, its properties and values can be unknown...
}
}
function in_object($value,$object) {
if (is_object($object)) {
foreach($object as $key => $item) {
if ($value==$item) return $key;
}
}
return false;
}
function manipulate_property($value,$object) {
if ($property = in_object($value,$object)) {
// value found. I can now use this property.
// I can simply echo'it (makes no sense, as I could instead simply echo "value")
echo "<br />I found the property holding this value: ".$object->$property;
// or (here comes the good part)
// change the property
$object->$property = "This is a changed value!";
echo "<br />I changed the value to: ".$object->$property;
// or return it for use in my program flow
return $property;
} else {
echo "Value NOT FOUND!<br />";
return false;
}
}
// imagine if some function creates the class conditionally...
if ( 1 == 1) {
$class = new My_Class("property","Unchanged Value");
} else {
$class = new My_Class("property","Some Other Value");
}
// now let's check if the value we want exists, and if yes, let's have some fun with it...
$property = manipulate_property("Unchanged Value",$class);
if ($property) {
$my_variable = $class->$property;
echo "<br />This is my variable now:".$my_variable;
} else $my_variable = $some_other_variable;
?>
Just run it to see for yourself!
I don't recommend it, because it's very bad practice but you can use get_object_vars.
Gets the accessible non-static properties of the given object according to scope.
There are other limitations you should refer to the documentation to see if it is suitable for you.
if(in_array('find me', get_object_vars($obj)))
This is the most efficient and correct solution. With some modifications it could be applied to check any data type present in any object.
if(gettype($object->var1->var2) == "string"){
echo "Present";
}
Related
I want to declare a variable inside a class with an unknown name
class Example {
function newVar($name, $value) {
$this->$name = $value;
}
}
And I want to use it that way
$c = new Example();
$c->newVar('MyVariableName', "This is my Value");
echo($c->MyVariableName);
The Important thing is, that I do not know the name of the variable. So I cannot put a public $MyVariable inside the class.
Is that in anyway possible? and if yes, can i do this with different scopes (private, protected, public) ?
U should use magic methods __get and __set (example without checking):
class Example {
private $data = [];
function newVar($name, $value) {
$this->data[$name] = $value;
}
public function __get($property) {
return $this->data[$property];
}
public function __set($property, $value) {
$this->data[$property] = $value;
}
}
$c = new Example();
$c->newVar('MyVariableName', "This is my Value");
echo($c->MyVariableName);
// This is my Value
$c->MyVariableName = "New value";
echo($c->MyVariableName);
// New value
See http://php.net/manual/en/language.oop5.magic.php
If i am understanding this correctly you can tweak a little bit by using key value array
class Example {
private $temp;
function __construct(){
$this->temp = array();
}
function newVar($name, $value) {
$this->temp[$name] = $value;
}
function getVar($name){
return $this->temp[$name];
}
}
$c = new Example();
$c->newVar('MyVariableName', "This is my Value");
echo($c->getVar('MyVariableName'));
Instead of using private you can use protected as well.
Your looking for magic calling. In PHP you can use the __call() function to do stuff like that. Have a look here: http://www.garfieldtech.com/blog/magical-php-call
Off the top of my head, something like
function __call($vari, $args){
if(isset($this->$vari){
$return = $this->$vari;
}else{
$return = "Nothing set with that name";
}
}
This will also work for private, protected and public. Can also use it to call methods as required in a class
Is PHP exists a function that detect the change of variable?
That is something like this:
//called when $a is changed.
function variableChanged($value) {
echo "value changed to " . $value;
}
$a = 1;
//attach the variable to the method.
$a.attachTo("variableChanged");
$a = 2;
$a = 3;
//expected output:
//value changed to 2
//value changed to 3
I know that it is easy to achieve if I use the "setter" method. But since I am working on some existing codes, I am not able to modify them. Can somebody tell me how to achieve my purpose? Thanks.
know that it is easy to achieve if I use the "setter" method. But since I am working on some existing codes, I am not able to modify them.
I assume that you can change some code, but not the object / class you are working with. If you cannot change any code at all this question would be useless.
What you can do is make your own class, extending the class you are working with, and adding your setter there. For all purposes you can not-override the parent setting, except for a magic setter on whatever you need to track. Track changes and then call the parent functions, so no changes in any other internal workings will be in effect.
This could only be achieved by wrapping your variable within a class, and implementing a onchange yourself.
ie.
class MyVarContainer {
var $internalVar = array();
function __get($name) {
return !empty($this->internalVar[$name]) $this->internalVar[$name] ? FALSE;
}
function __set($name, $value) {
$oldval = $this->$name;
$this->internalVar[$name] = $value;
if($oldval !== FALSE) {
onUpdated($name, $oldval, $value);
} else {
onCreated($name, $value);
}
}
function onCreated($name, $value) {
}
function onUpdated($name, $oldvalue, $newvalue) {
}
}
You could revised your code as simple like this just to produce that expected output you want.
function variableChanged($value) {
return "value changed to " . $value;
}
$a = 1;
echo $a = variableChanged(2);
echo '<br/>';
echo $a = variablechanged(3);
=================
//output
value changed to 2
value changed to 3
or using a class like this....
class VariableHandler{
private $Variable;
function setVariable($initialValue = NULL){
$this->Variable = $initialValue;
return $initialValue;
}
function changeValue($newValue = NULL){
$this->Variable = $newValue;
return "value has change to ". $newValue;
}
}
$var = new VariableHandler;
echo $a = $var->setVariable(1);
echo '<br/>';
echo $var->changeValue(2);
echo '<br/>';
echo $var->changeValue(3);
=================
//output
value changed to 2
value changed to 3
Besides using a debugger:
The SplObserver interface is used alongside SplSubject to implement
the Observer Design Pattern.
http://www.php.net/manual/en/class.splobserver.php
Or the magic methods __get() and __set(): Encapsulating the variable into a class, you could implement a event handler yourself and register the change of a variable. Also you could attach callbacks like here:
<?php
header("content-type: text/plain");
class WatchVar {
private $data = array();
private $org = array();
private $callbacks = array();
public function __set($name, $value) {
if (!array_key_exists($name, $this->data)) {
$this->org[$name] = $value;
} else {
//variable gets changed again!
$this->triggerChangedEvent($name, $value);
}
$this->data[$name] = $value;
}
public function &__get($name) {
if (array_key_exists($name, $this->data)) {
if ($this->data[$name] != $this->org[$name]) {
//variable has changed, return original
//return $this->org[$name];
//or return new state:
return $this->data[$name];
} else {
//variable has not changed
return $this->data[$name];
}
}
}
public function addCallback($name, $lambdaFunc) {
$this->callbacks[$name] = $lambdaFunc;
}
protected function triggerChangedEvent($name, $value) {
//$this->data[$name] has been changed!
//callback call like:
call_user_func($this->callbacks[$name], $value);
}
}
$test = new WatchVar;
$test->addCallback('xxx', function($newValue) { echo "xxx has changed to {$newValue}\n"; });
$test->xxx = "aaa";
echo $test->xxx . "\n";
//output: aaa
$test->xxx = "bbb";
//output: xxx has changed to bbb
echo $test->xxx . "\n";
//output bbb
function messyFunction(&$var) {
$var = "test";
}
messyFunction($test->xxx);
//output:
I was wondering if you could get the class name and property name from a property reference in PHP?
class Test {
public static $TestProp;
}
GetDoc(& Test::$TestProp);
function GetDoc($prop) {
$className = getClassName($prop);
$propertyName = getPropertyName($prop);
}
what I'm looking for is if it is possible to create the functions getClassName and getPropertyName?
What you want is basically not possible; a property doesn't know its parent structure.
The only sane thing I could think of is to use reflection for it:
class Test
{
public static $TestProp = '123';
}
//GetDoc(& Test::$TestProp);
GetDoc('Test', 'TestProp');
function GetDoc($className, $propName)
{
$rc = new ReflectionClass($className);
$propValue = $rc->getStaticPropertyValue($propName);
}
Within the Test class you could use __CLASS__ as a convenient reference for the class name.
I have figured out the way to get this to work there is a lot of magic that goes on just to get this to work, but in my case it's worth it.
class Test {
private $props = array();
function __get($name) {
return new Property(get_called_class(), $name, $this->props[$name]);
}
function __set($name, $value) {
$props[$name] = $value;
}
}
class Property {
public $name;
public $class;
public $value;
function __construct($class, $name, $value) {
$this->name = $name;
$this->class = $class;
$this->value = $value;
}
function __toString() {
return $value.'';
}
}
function GetClassByProperty($prop) {
return $prop->class.'->'.$prop->name;
}
$t = new Test();
$t->Name = "Test";
echo GetClassByProperty($t->Name);
this example yes I know it's complex, but it does the job how I'd want it to, will print out "Test->Name" I can also get the value by saying $prop->value. If I want to compare the value to another object I can simply do this:
if($t->Name == "Test") { echo "It worked!!"; }
hope this isn't too confusing but it was a fun exploration into PHP.
Php have a build in function called get_class
To avoid getting the error message as in this previous question, I decided to change the class with __get() like this below,
class property
{
public function __get($name)
{
return isset($this->$name) ? $this->$name : new property;
}
}
class objectify
{
public function array_to_object($array = array(), $property_overloading = false)
{
# if $array is not an array, let's make it array with one value of former $array.
if (!is_array($array)) $array = array($array);
# Use property overloading to handle inaccessible properties, if overloading is set to be true.
# Else use std object.
if($property_overloading === true) $object = new property();
else $object = new stdClass();
foreach($array as $key => $value)
{
$key = (string) $key ;
$object->$key = is_array($value) ? self::array_to_object($value, $property_overloading) : $value;
}
return $object;
}
}
$object = new objectify();
$type = null;
$type = $object->array_to_object($type,true);
var_dump($type->a->b->c);
so I get this result in the end,
object(property)#3 (0) { }
but it is still not perfect. as my understanding, the above solution processes the object in a chain like this,
$type = object{}->object{}->object{}
so I wonder if I can find whether it is the last chain and it is empty then just output a null?
$type = object{}->object{}->NULL
is it possible with PHP?
EDIT:
I have thought of an idea which is to count how many times the property class has been instantiated,
class property
{
public static $counter = 0;
function __construct() {
self::$counter++;
}
public function __get($name)
{
if(isset($this->$name))
{
return $this->$name;
}
elseif(property::$counter < 3)
{
return new property;
}
else
{
return null;
}
}
}
but my only problem is how to make the number 3 dynamic. Any ideas?
Sounds like you're looking for a PHP version of Groovy's ?. operator: http://groovy.codehaus.org/Null+Object+Pattern
Afaik, you can't overload or create a new operator in PHP. You could perhaps simulate it by passing all of your nested calls to a function, and the function knows when to return null.
Edit: other options posted here - http://justafewlines.com/2009/10/groovys-operator-in-php-sort-of/
I've been fooling with ArrayAccess and PHP's magic (__get, __set) for awhile now, and I'm stuck.
I'm trying to implement a class in which some properties, which are arrays, are read only. They will be set initially by the constructor, but should not be modifiable thereafter.
Using __get magic by reference, I can access array elements arbitrarily deep in the properties, and I was thinking I can throw exceptions when those properties are targeted via __set.
The problem is though, when I'm accessing the value of an array element, PHP is calling __get to return that part of the array by reference, and I have no knowledge of whether or not its a read or write action.
(The worst part is I knew this going in, but have been fooling with ArrayAccess as a possible workaround solution, given the properties were instances of an implemented object)
Simple example:
class Test{
public function &__get($key){
echo "[READ:{$key}]\n";
}
public function __set($key, $value){
echo "[WRITE:{$key}={$value}]\n";
}
}
$test = new Test;
$test->foo;
$test->foo = 'bar';
$test->foo['bar'];
$test->foo['bar'] = 'zip';
And the output:
[READ:foo]
[WRITE:foo=bar]
[READ:foo]
[READ:foo] // here's the problem
Realistically, I only need the value foo (as per my example) anyways, but I need to know it's a write action, not read.
I've already half accepted that this cannot be achieved, but I'm still hopeful. Does anyone have any idea how what I'm looking to accomplish can be done?
I was considering some possible workarounds with ArrayAccess, but so far as I can tell, I'll end up back at this spot, given I'm going to use the property notation that invokes __get.
Update: Another fun day with ArrayAccess.
(This is a different issue, but I suppose it works in. Posting just for kicks.)
class Mf_Params implements ArrayAccess{
private $_key = null;
private $_parent = null;
private $_data = array();
private $_temp = array();
public function __construct(Array $data = array(), $key = null, self $parent = null){
$this->_parent = $parent;
$this->_key = $key;
foreach($data as $key => $value){
$this->_data[$key] = is_array($value)
? new self($value, $key, $this)
: $value;
}
}
public function toArray(){
$array = array();
foreach($this->_data as $key => $value){
$array[$key] = $value instanceof self
? $value->toArray()
: $value;
}
return $array;
}
public function offsetGet($offset){
if(isset($this->_data[$offset])){
return $this->_data[$offset];
}
// if offset not exist return temp instance
return $this->_temp[$offset] = new self(array(), $offset, $this);
}
public function offsetSet($offset, $value){
$child = $this;
// copy temp instances to data after array reference chain
while(!is_null($parent = $child->_parent) && $parent->_temp[$child->_key] === $child){
$parent->_data[$child->_key] = $parent->_temp[$child->_key];
$child = $parent;
}
// drop temp
foreach($child->_temp as &$temp){
unset($temp);
}
if(is_null($offset)){
$this->_data[] = is_array($value)
? new self($value, null, $this)
: $value;
}else{
$this->_data[$offset] = is_array($value)
? new self($value, $offset, $this)
: $value;
}
}
public function offsetExists($offset){
return isset($this->_data[$offset]);
}
public function offsetUnset($offset){
unset($this->_data[$offset]);
}
}
You need to use a second class, implementing ArrayAccess, to use instead of your arrays. Then you will be able to control what is added to the array with the offsetSet() method:
class ReadOnlyArray implements ArrayAccess {
private $container = array();
public function __construct(array $array) {
$this->container = $array;
}
public function offsetSet($offset, $value) {
throw new Exception('Read-only');
}
public function offsetExists($offset) {
return isset($this->container[$offset]);
}
public function offsetUnset($offset) {
unset($this->container[$offset]);
}
public function offsetGet($offset) {
if (! array_key_exists($offset, $this->container)) {
throw new Exception('Undefined offset');
}
return $this->container[$offset];
}
}
You can then initialize your ReadOnlyArray with your original array:
$readOnlyArray = new ReadOnlyArray(array('foo', 'bar'));
You could not return by ref, which would solve the problem of changability, but would not allow changing of some values that are allowed to be changed.
Alternatively you need to wrap every returned array in ArrayAccess, too - and forbid write access there.