I want to pull all info about a file from a files table, but that table's structure might change.
So, I'd like to pull all the field names from the table and use them to generate the class variables that contain the information, then store the selected data to them.
Is this possible?
Yes you can, see php overloading.
http://php.net/manual/en/language.oop5.overloading.php
Quick Example: ( Not this isn't great usage )
<?php
class MyClass{
var $my_vars;
function __set($key,$value){
$this->my_vars[$key] = $value;
}
function __get($key){
return $this->my_vars[$key];
}
}
$x = new MyClass();
$x->test = 10;
echo $x->test;
?>
Sample
<?php
class TestClass
{
public $Property1;
public function Method1()
{
$this->Property1 = '1';
$this->Property2 = '2';
}
}
$t = new TestClass();
$t->Method1();
print( '<pre>' );
print_r( $t );
print( '</pre>' );
?>
Output
TestClass Object
(
[Property1] => 1
[Property2] => 2
)
As you can see, a property that wasn't defined was created just by assigning to it using a reference to $this. So yes, you can define class variable from within a class method.
Related
I'm not good at php OOP.
class Example{
public $name;
public $age;
}
$example = new Example();
I would like to get the property name as string, like-
echo get_property_name($example->name); //should echo 'name'
//OR,
echo $example->name->toString(); //should echo 'name'
Please note that, I don't want to write the property name in a string or variable like-
$property = $class->getProperty('name');
I don't want to get the value of property, I want to get the name of the property as a string.
Is it possible in php?
You can build a helper function with get_object_vars(). Because you already know the var-name, the function only checks, if this exists in the object and returns the var as string:
function get_property_name($oObject, $sString) {
$aObjectVars = get_object_vars($oObject);
if( isset($aObjectVars[$sString]) ) {
return $sString;
}
return false; // object var not exists
}
In PHP you can introspect a class, function, or... with ReflectionClass:
<?php
class Example
{
public $name;
public $age;
}
$example = new Example();
$ref = new ReflectionClass($example);
$props = $ref->getProperties();
foreach($props as $prop) {
var_dump($prop->name);
}
The output:
string(4) "name"
string(3) "age"
one other option would be a trait with following methods.
public function toArray(): array
{
return (array) $this;
}
public function properties(): array
{
return array_keys($this->toArray());
}
We do not know your use case. If you write a DTO, Reflection might be your desired way. If you write a model with some extra sugar, you could store all attributes in an array to load and edit them. Probably two arrays so you could compare edited and loaded values. with __isset, __get, __set you can always preload attributes.
How can I create a property from a given argument inside a object's method?
class Foo{
public function createProperty($var_name, $val){
// here how can I create a property named "$var_name"
// that takes $val as value?
}
}
And I want to be able to access the property like:
$object = new Foo();
$object->createProperty('hello', 'Hiiiiiiiiiiiiiiii');
echo $object->hello;
Also is it possible that I could make the property public/protected/private ? I know that in this case it should be public, but I may want to add some magik methods to get protected properties and stuff :)
I think I found a solution:
protected $user_properties = array();
public function createProperty($var_name, $val){
$this->user_properties[$var_name] = $val;
}
public function __get($name){
if(isset($this->user_properties[$name])
return $this->user_properties[$name];
}
do you think it's a good idea?
There are two methods to doing it.
One, you can directly create property dynamically from outside the class:
class Foo{
}
$foo = new Foo();
$foo->hello = 'Something';
Or if you wish to create property through your createProperty method:
class Foo{
public function createProperty($name, $value){
$this->{$name} = $value;
}
}
$foo = new Foo();
$foo->createProperty('hello', 'something');
The following example is for those who do not want to declare an entire class.
$test = (object) [];
$prop = 'hello';
$test->{$prop} = 'Hiiiiiiiiiiiiiiii';
echo $test->hello; // prints Hiiiiiiiiiiiiiiii
Property overloading is very slow. If you can, try to avoid it. Also important is to implement the other two magic methods:
__isset();
__unset();
If you don't want to find some common mistakes later on when using these object "attributes"
Here are some examples:
http://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.members
EDITED after Alex comment:
You can check yourself the differences in time between both solutions (change $REPEAT_PLEASE)
<?php
$REPEAT_PLEASE=500000;
class a {}
$time = time();
$a = new a();
for($i=0;$i<$REPEAT_PLEASE;$i++)
{
$a->data = 'hi';
$a->data = 'bye'.$a->data;
}
echo '"NORMAL" TIME: '.(time()-$time)."\n";
class b
{
function __set($name,$value)
{
$this->d[$name] = $value;
}
function __get($name)
{
return $this->d[$name];
}
}
$time=time();
$a = new b();
for($i=0;$i<$REPEAT_PLEASE;$i++)
{
$a->data = 'hi';
//echo $a->data;
$a->data = 'bye'.$a->data;
}
echo "TIME OVERLOADING: ".(time()-$time)."\n";
Use the syntax: $object->{$property}
where $property is a string variable and
$object can be this if it is inside the class or any instance object
Live example: http://sandbox.onlinephpfunctions.com/code/108f0ca2bef5cf4af8225d6a6ff11dfd0741757f
class Test{
public function createProperty($propertyName, $propertyValue){
$this->{$propertyName} = $propertyValue;
}
}
$test = new Test();
$test->createProperty('property1', '50');
echo $test->property1;
Result: 50
I'm having an issue calling a variable thats included in a class. What am I missing here? Thank you in advance for the support. Very much appreciated.
//index2.php
$var2 = 'var2';
//index.php
class something {
__construct() {
include('index2.php');
}
}
$run_it = new something();
echo $run_it->var2; //how do I call var2?
You could do this. Kind of a strange way to do things but here goes:
index.php
<?php
class something{
function __construct() {
include('index2.php');
}
}
//s1
$s1 = new something();
$s1->var2 = 'var2 changed';
//s2
$s2 = new something();
//print em out
print_r($s1);
print_r($s2);
index2.php
<?php
$this->var2 = 'var2'; //$this pseudo-variable works because we're including index2.php within the scope of our class instance
?>
Output
$ php a.php
something Object
(
[var2] => var2 changed
)
something Object
(
[var2] => var2
)
You cannot extend property's of a class with including files. The class is defined as it is written. You have the following ways to add code to a class dynamically.
Extend a class.
Use traits (copy pasting functions into a class)
Use magic methods (__call, __get, __set)
This example will print variables defined in the global scope (like your example) as you wanted it to do.
However, this is not the way it should be used and I suggest finding a different method of writing your class.
include 'somefile.php'; // <?php $var3 = 'testing' ?>
class foo{
public $var2 = 'var2'; # should be declared within the class.
public function __get($name){
// property 'var3' is not defined in the class so this method is magically called instead.
if(isset($GLOBALS[$name])){
return $GLOBALS[$name]; // Here we return the value $var3 defined in the global scope.
} else {
trigger_error("Call to undefined variable '$name'");
}
}
public function __construct(){ # Missed function statement.
echo 'hello';
}
}
$c = new foo();
echo $c->var3; // testing
If your index2.php contains this:
$var2 = 'var2';
Then you can include that file to get access to $var2. You can then pass that variable to your something constructor as an argument:
//index.php
class something {
public $var2;
public function __construct($arg) {
$this->var2 = $arg;
}
}
include 'index2.php';
$run_it = new something($var2);
echo $run_it->var2; // echos 'var2'
It's obvious there are other ways to do something like what you're attempting to do (there is usually more than one way to do most things), but really the most sensible way to get external data into your object is to pass it via constructor arguments.
If you don't do this, the class will forever depend on some other file existing in the correct location relative to the class or calling file, with all of the correct variables set in it. If that file is altered or moved, objects of that class may not function properly if they can even be instantiated at all.
I agree with Xorifelse, you can do it with traits. example.
fields.php
trait Aa {
public $fields = [
"name"=>"string->5",
"number"=>"integer->3",
];
}
traits.php
include('fields.php');
class ABC {
use Aa;
public function __set($field,$value)
{
if(array_key_exists($field,$this->fields))
{
$this->fields[$field] = $value;
}
else
{
$this->fields[$field] = null;
}
}
public function __get($field)
{
if(array_key_exists($field,$this->fields))
{
return $this->fields[$field];
}
else
{
return null;
}
}
}
$a = new ABC();
$a->number = 111;
var_dump($a->fields);
array(2) {
["name"]=>
string(9) "string->5"
["number"]=>
int(111)
}
var_dump($a->number);
int(111)
You can take advantage of get_defined_vars. Assuming your variables are in a file (e.g. filevars.php):
filevars.php
<?php
$name = 'myName';
$address = 'myAddress';
$country = 'myCountry';
$phones = array('123456789','987654321');
?>
You can add a method to your class (getVars) and define a property (vars) that wraps all variables existing in filevars.php:
class-test.php
<?php
class Test
{
public $vars;
function getVars()
{
include ('filevars.php');
$this->vars = get_defined_vars();
}
}
?>
Usage
<?php
include ('class-test.php');
$myClass = new Test();
$myClass->getVars();
print_r($myClass->vars);
?>
Output:
Array
{
[name] => myName
[address] => myAddress
[country] => myCountry
[phones] => Array
{
[0] => 123456789
[1] => 987654321
}
}
You can also refer any individual included variable, e.g.:
echo $myClass->vars['country']; // myCountry
I'm quite inexperienced with OOP PHP but here's my question...let's say I have this class with one property:
class myClass {
public $property = array();
public function getProperty() {
return $this->property;
}
}
How would it be possible to change the value of $property without altering the class itself in any way, or by instantiating an object out of it, then changing its property. Is there any other way of doing it? Using scope resolution?
Hope that makes sense, any help would be much appreciated.
What you want is a static member
class MyClass {
public static $MyStaticMember = 0;
public function echoStaticMember() {
echo MyClass::$MyStaticMember;
//note you can use self instead of the class name when inside the class
echo self::$MyStaticMember;
}
public function incrementStaticMember() {
self::$MyStaticMember++;
}
}
then you access it like
MyClass::$MyStaticMember = "Some value"; //Note you use the $ with the variable name
Now any instances and everything will see the same value for whatever the static member is set to so take for instance the following
function SomeMethodInAFarFarAwayScript() {
echo MyClass::$MyStaticMember;
}
...
MyClass::$MyStaticMember++; //$MyStaticMember now is: 1
$firstClassInstance = new MyClass();
echo MyClass::$MyStaticMember; //will echo: 1
$firstClassInstance->echoStaticMember(); //will echo: 1
$secondInstance = new MyClass();
$secondInstance->incrementStaticMember(); // $MyStaticMember will now be: 2
echo MyClass::$MyStaticMember; //will echo: 2
$firstClassInstance->echoStaticMember(); //will echo: 2
$secondInstance->echoStaticMember(); //will echo: 2
SomeMethodInAFarFarAwayScript(); //will echo: 2
PHPFiddle
I hope this is what you are looking for
<?php
class myClass {
public $property = array();
public function getProperty() {
print_r($this->property);
}
}
$a = new myClass();
$x = array(10,20);
$a->property=$x; //Setting the value of $x array to $property var on public class
$a->getProperty(); // Prints the array 10,20
EDIT :
As others said , yes you need the variable to be declared as static (if you want to modify the variable without creating new instance of the class or extending it)
<?php
class MyClass {
public static $var = 'A Parent Val';
public function dispData()
{
echo $this->var;
}
}
echo MyClass::$var;//A Parent Val
MyClass::$var="Replaced new var";
echo MyClass::$var;//Replacced new var
?>
In PHP, is it possible to have a function within a class that's non-static, but also isn't an instance function?
For example, if I have the following:
class A
{
public $i;
function setValue($val) {
$this->i = $val;
}
}
$a1 = new A;
$a1->setValue(5);
echo $a1->i; // result: 5
$a2 = new A;
$a2->setValue(2);
echo $a2->i; // result: 2
Can I add a function to that class that can have "visibility" of all instances of itself so I can do something like so (which I know doesn't work, but communicates my thought):
class A
{
public $i;
function setValue($val) {
$this->i = $val;
}
function getTotal() {
return sum($this->i); // I know sum() isn't a built-in function, but it helps explain what I want. I'm not sure if $this makes sense here too.
}
}
$a1 = new A;
$a1->setValue(5);
echo $a1->i; // result: 5
$a2 = new A;
$a2->setValue(2);
echo $a2->i; // result: 2
echo A::getTotal(); // returns: 7
I guess A::getTotal() means getTotal() would need to be static, but if it was static then it wouldn't then be able to "see" each class instance.
Is this type of thing possible, and what's the correct terminology I should be using?
No, there is no built-in instance enumeration, you will need to keep references to each instantiated object yourself. You can keep an array of instances in a static property of the class and populate it in your __construct(). You can then have a static method loop over this array and process all instances.
I think you would like something like this:
class A
{
public $i;
function setValue($val) {
$this->i = $val;
}
}
$a1 = new A;
$a1->setValue(5);
echo $a1->i; // result: 5
$a2 = new A;
$a2->setValue(2);
echo $a2->i; // result: 2
$total = 0;
foreach( get_defined_vars() as $name => $obj ) {
if ( $obj instanceof A ) {
$total += $obj->i;
}
}
echo $total; // returns: 7
The function you need here is "get_defined_vars". But it only gets the variables within the current scope!
Just make the class member of the sum static as well. If you do this, then you will need to make sure it's maintained properly within each class (i.e. setValue needs to update that sum appropriarely).
This is probably not a great way to do things, though. I think it would get pretty confusing. In what context do you need the sum that you don't have access to all the instances?
Are you looking for a protected function foo($s){...} which the class can use but cannot be accessed from the outside? (PHP5 only)