How can I create dynamically objects based on array values in php? - php

I'ld like to dynamically create as many object as present in my $instance array (e.g. domain1_com and domain2_com) and give them the name of array value (e.g. domain1_com and domain2_com) so I can access it through these names (e.g. domain1_com->example()).
Is it possible? I tried something like this but obviously doesn't work.
class myClass
{
public static function getInstances()
{
// I connect to the database and execute the query
$sql = "SELECT * FROM my_table";
$core = Core::getInstance();
$stmt = $core->dbh->prepare($sql);
if ($stmt->execute()) {
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// Read values in my array
foreach ($results as $instance) {
$obj = $instance["domain"]);
// return 2 values: domain1_com and domain2_com
$obj = new myClass();
}
}
public function example()
{
echo "This is an instance";
}
}
myClass::getInstances();
$domain1_com->example();
$domain2_com->example();

You can use variable variables.
$name = "foo";
$$name = new bar();
is the same as
$foo = new bar();
You cannot access the variables created inside getInstances outside of that method. They are local, not global.
Try this code:
class myClass
{
public static function getInstances()
{
$results = array('domain1_com', 'domain2_com');
foreach ($results as $instance) {
$$instance = new myClass();
// This is equivalent to "$domainX_com = new myClass();".
// Writing that code here would define a _local_ variable named 'domainX_com'.
// This being a method inside a class any variables you define in here are _local_,
// so you can't access them' _outside_ of this method ('getInstances')
}
// this will work, we are inside 'getInstances'
$domain1_com->example();
$domain2_com->example();
}
public function example()
{
echo "This is an instance";
}
}
myClass::getInstances();
// this won't work. $domainX_com are not accessible here. they only exist _inside_ 'getInstances'
// It's basic OOP.
// so this code will crash
$domain1_com->example();
$domain2_com->example();
It will produce this output:
This is an instance
This is an instance
E_NOTICE : type 8 -- Undefined variable: domain1_com -- at line 32
E_ERROR : type 1 -- Call to a member function example() on a non-object -- at line 32
You need a way to access those variables. I'd use this:
class myClass
{
private static $instances = array();
public static function getInstances()
{
$results = array('domain1_com', 'domain2_com');
foreach ($results as $instanceName) {
self::$instances[$instanceName] = new myClass();
}
}
public static function getInstance($instanceName) {
return self::$instances[$instanceName];
}
public function example()
{
echo "This is an instance";
}
}
myClass::getInstances();
// this will work
myClass::getInstance('domain1_com')->example();
myClass::getInstance('domain2_com')->example();

Related

Why isn't the array I return in my __construct class available in the following function?

I've written a class which in the construct accesses the db and gets a list of names. These names go into an associative array e.g. ('name' => 'id').
i.e. the point is to pass in the name to get back an ID:
$id = names::nameToId('some name');
print $id;
// prints int
The problem is when I try and return the array from the construct I get an error:
Notice: Undefined variable: nameArray in (etc)
Here is the code so far:
class nameToId {
public $nameArray;
private $mysqli;
public function __construct($mysqli) {
...
while($row = mysqli_fetch_assoc($res)) {
$nameArray[$row['name']] = $row['id'];
}
return $nameArray;
}
static public function nameToId($name) {
$nameId = $nameArray[$name];
return $nameId;
}
}
$namesToId = new nameToId($mysqli);
$nameId = $namesToId::nameToId('some name');
echo $nameId;
Why doesn't $nameArray get passed to nameToId()? I'm new to classes, and I thought by declaring $nameArray as public when I first create the class that it would make it available. I have also tried to make it global even though I know that is not good form but even still it didn't work.
Because you cannot return anything from a constructor. Any return value is being ignored and just goes into the aether. $nameArray is a local variable and is not shared in any other scope, i.e. you can't access it in nameToId. Further, since nameToId is static, it won't have access to data from any non-static methods like __construct to begin with.
You probably want something like this:
class nameToId {
public $nameArray;
private $mysqli;
public function __construct($mysqli) {
...
while ($row = mysqli_fetch_assoc($res)) {
$this->nameArray[$row['name']] = $row['id'];
}
}
public function nameToId($name) {
return $this->nameArray[$name];
}
}
$namesToId = new nameToId($mysqli);
echo $namesToId->nameToId('some name');
Fix your code:
class nameToId {
public static $nameArray;
private $mysqli;
public function __construct($mysqli) {
$this->mysqli = $mysqli;
$sql = 'SELECT id, name FROM teams';
$res = mysqli_query($this->mysqli,$sql);
while($row = mysqli_fetch_assoc($res)) {
self::$nameArray[$row['name']] = $row['id'];
}
}
static public function nameToId($name) {
$nameId = self::$nameArray[$name];
return $nameId;
}
}
$namesToId = new nameToId($mysqli);
$nameId = $namesToId::nameToId('some name');
echo $nameId;

Create properties in a class with the names and values of all the variables passed to the constructor

I want to create properties in a class with the names of all of the variables passed to the constructor and with the same values.
I was able to do it with strings:
class test {
public function __construct() {
$args = func_get_args();
foreach($args as $arg) {
$this->{$arg} = $arg;
$this->init();
}
}
public function init() {
echo $this->one;
}
}
// Output: "one"
$obj = new test("one");
But I don't know how I can do it with variables. I tried this:
class test {
public function __construct() {
$args = func_get_args();
foreach($args as $arg) {
$this->{$arg} = $arg;
$this->init();
}
}
public function init() {
echo $this->one;
}
}
$one = "one!";
$obj = new test($one);
Output:
Notice: Undefined property: test::$one on line 13
What I wanted it to output:
one!
Try:
public function init() {
echo $this->{'one!'};
}
No, it's not possible in any sane way to get the name of a variable used in calling code inside the callee. The sanest method is to use new test(compact('one')), which gives you a regular key-value array inside test::__construct, which you can loop through.
http://php.net/compact

PHP get_object_vars from subclass

Question:
How to push $param from load() to $data property in class A?
Therefor I can use get_class_vars get_object_vars to load them.
Each time I use load function, it will add $param to $data property.
Example:
<?php
class Test {
public function testing($str) { echo $str; }
}
class A {
public $data = array();
public function load($param) {
array_push($this->data, $param); // not adding $param to $data property
return $param = new $param;
}
}
class B {
public $a;
public function __construct() {
$this->a = new A();
var_dump(get_object_vars($this->a)); // showing empty $data property
}
}
// Usage
$b = new B();
$test = $b->a->load('test');
$test->testing('hello');
Edit:
used get_object_vars($this->a)
get_class_vars only shows default public variables. Use get_object_vars($this->a) instead; this should work.

Inheritance in PHP - Creating child instance and calling parent method

I have something like this:
class MyParent {
protected static $object;
protected static $db_fields;
public function delete() {
// delete stuff
}
public static function find_by_id($id = 0) {
global $database;
$result_array = self::find_by_sql("SELECT * FROM " . static::$table_name . " WHERE id=" . $database -> escape_value($id) . " LIMIT 1");
return !empty($result_array) ? array_shift($result_array) : false;
}
public static function find_by_sql($sql = "") {
global $database;
// Do Query
$result_set = $database -> query($sql);
// Get Results
$object_array = array();
while ($row = $database -> fetch_array($result_set)) {
$object_array[] = self::instantiate($row);
}
return $object_array;
}
private static function instantiate($record) {
$object = self::$object;
foreach ($record as $attribute => $value) {
if (self::has_attribute($attribute)) {
$object -> $attribute = $value;
}
}
return $object;
}
}
class TheChild extends MyParent {
protected static $db_fields = array('id', 'name');
protected static $table_name = "my_table";
function __construct() {
self::$object = new TheChild;
}
}
$child= TheChild::find_by_id($_GET['id']);
$child->delete();
I get this: Call to undefined method stdClass::delete() referring to the last line above. What step am I missing for proper inheritance?
You never actually instanciate the TheChild class, which should be done by
$var = new TheChild();
except in TheChild constructor itself.
So, the static $object field is never affected (at least in your example), so affecting a field to it (the line $object -> $attribute = $value; ) causes the creation of an stdClass object, as demonstrated in this interactive PHP shell session:
php > class Z { public static $object; }
php > Z::$object->toto = 5;
PHP Warning: Creating default object from empty value in php shell code on line 1
php > var_dump(Z::$object);
object(stdClass)#1 (1) {
["toto"]=>
int(5)
}
This object does not have a delete method.
And as said before, actually creating a TheChild instance will result in an infinite recursion.
What you want to do is this, probably:
class TheChild extends MyParent {
protected static $db_fields = array('id', 'name');
protected static $table_name = "my_table";
function __construct() {
self::$object = $this;
}
}
Edit: Your updated code shows a COMPLETE different Example:
class MyParent {
protected static $object;
public function delete() {
// delete stuff
}
}
class TheChild extends MyParent {
function __construct() {
self::$object = new TheChild;
}
}
$child = new TheChild;
$child->delete();
Calling "Child's" Constructor from within "Child's" Constructor will result in an infinite loop:
function __construct() {
self::$object = new TheChild; // will trigger __construct on the child, which in turn will create a new child, and so on.
}
Maybe - i dont know what you try to achieve - you are looking for:
function __construct() {
self::$object = new MyParent;
}
ALSO note, that the :: Notation is not just a different Version for -> - it is completely different. One is a Static access, the other is a access on an actual object instance!

get a list of all variables defined outside a class by user

i have something like this:
class foo
{
//code
}
$var = new foo();
$var->newVariable = 1; // create foo->newVariable
$var->otherVariable = "hello, im a variable"; //create foo->otherVariable
i can get in class foo a list of all variables defined outside by user (newVariable, otherVariable,etc)? Like this:
class foo
{
public function getUserDefined()
{
// code
}
}
$var = new foo();
$var->newVariable = 1; // create foo->newVariable
$var->otherVariable = "hello, im a variable"; //create foo->otherVariable
var_dump($var->getUserDefined()); // returns array ("newVariable","otherVariable");
Thanks!.
Yes, using get_object_vars() and get_class_vars():
class A {
var $hello = 'world';
}
$a = new A();
$a->another = 'variable';
echo var_dump(get_object_vars($a));
echo '<hr />';
// Then, you can strip off default properties using get_class_vars('A');
$b = get_object_vars($a);
$c = get_class_vars('A');
foreach ($b as $key => $value) {
if (!array_key_exists($key,$c)) echo $key . ' => ' . $value . '<br />';
}
What is your goal? Imo it's not very good practice (unless you really know what you are doing). Maybe it's good idea consider create some class property like "$parameters" and then create setter and getter for this and use it in this way:
class foo {
private $variables;
public function addVariable($key, $value) {
$this->variables[$key] = $value;
}
public function getVariable($key) {
return $this->variables[$key];
}
public function hasVariable($key) {
return isset($this->variables[$key]);
}
(...)
}
$var = new foo();
$var->addVariable('newVariable', 1);
$var->addVariable('otherVariable', "hello, im a variable");
And then you can use it whatever you want, for example get defined variable:
$var->getVariable('otherVariable');
To check if some var is already defined:
$var->hasVariable('someVariable')
get_class_vars() http://php.net/manual/en/function.get-class-vars.php
You question is not clear though.
$var->newVariable = 1;
there are two possible contex of above expression
1) you are accessing class public variables.
like
class foo
{
public $foo;
public function method()
{
//code
}
}
$obj_foo = new foo();
$obj_foo->foo = 'class variable';
OR
2) you are defining class variable runtime using _get and _set
class foo
{
public $foo;
public $array = array();
public function method()
{
//code
}
public function __get()
{
//some code
}
public function __set()
{
// some code
}
}
$obj_foo = new foo();
$obj_foo->bar= 'define class variable outside the class';
so in which context your question is talking about?

Categories