I have a class like this:
class someClass {
public static function getBy($method,$value) {
// returns collection of objects of this class based on search criteria
$return_array = array();
$sql = // get some data "WHERE `$method` = '$value'
$result = mysql_query($sql);
while($row = mysql_fetch_assoc($result)) {
$new_obj = new $this($a,$b);
$return_array[] = $new_obj;
}
return $return_array;
}
}
My question is: can I use $this in the way I have above?
Instead of:
$new_obj = new $this($a,$b);
I could write:
$new_obj = new someClass($a,$b);
But then when I extend the class, I will have to override the method. If the first option works, I won't have to.
UPDATE on solutions:
Both of these work in the base class:
1.)
$new_obj = new static($a,$b);
2.)
$this_class = get_class();
$new_obj = new $this_class($a,$b);
I have not tried them in a child class yet, but I think #2 will fail there.
Also, this does not work:
$new_obj = new get_class()($a,$b);
It results in a parse error: Unexpected '('
It must be done in two steps, as in 2.) above, or better yet as in 1.).
Easy, use the static keyword
public static function buildMeANewOne($a, $b) {
return new static($a, $b);
}
See http://php.net/manual/en/language.oop5.late-static-bindings.php.
You may use ReflectionClass::newInstance
http://ideone.com/THf45
class A
{
private $_a;
private $_b;
public function __construct($a = null, $b = null)
{
$this->_a = $a;
$this->_b = $b;
echo 'Constructed A instance with args: ' . $a . ', ' . $b . "\n";
}
public function construct_from_this()
{
$ref = new ReflectionClass($this);
return $ref->newInstance('a_value', 'b_value');
}
}
$foo = new A();
$result = $foo->construct_from_this();
Try using get_class(), this works even when the class is inherited
<?
class Test {
public function getName() {
return get_class() . "\n";
}
public function initiateClass() {
$class_name = get_class();
return new $class_name();
}
}
class Test2 extends Test {}
$test = new Test();
echo "Test 1 - " . $test->getName();
$test2 = new Test2();
echo "Test 2 - " . $test2->getName();
$test_initiated = $test2->initiateClass();
echo "Test Initiated - " . $test_initiated->getName();
When running, you'll get the following output.
Test 1 - Test
Test 2 - Test
Test Initiated - Test
Related
When generating an object this way AND executing a method, PHP gives an error.
class A {
static public function b() {
$o = new get_called_class(); // works
$class = get_called_class();
$o = new $class; // works
$o = (new $class)->method(); // works
$o = (new get_called_class())->method(); // doesn't work
// error message: Class '...\get_called_class' not found
$o = (new (get_called_class()))->method(); // doesn't work
// error message: syntax error, unexpected '('
}
}
Why does the last lines fail?
How to write it in one line?
Unfortunately you can't do it directly with the function's return value, but you can save it into a variables and use the variable. You can also use static or self constants.
$class = get_called_class();
$o = (new $class())->method();
$o = (new static())->method();
$o = (new self())->method();
Not possible at all. If you want to use an instance, store it in a variable.
class MyClass {
public function method(): string {
return "Hello World";
}
}
$instance = new MyClass();
$result = $instance->method();
You could work around if you do not need an instance by using a static method.
class MyClass {
public static function method(): string {
return "Hello World";
}
}
$result = MyClass::method();
i'm writing a php class that is like an orm.
I have a method, that can be called statically or instanciated, and it must work in both cases.
Can you see what's wrong.
Basically is an object called Model.
When created it creates a table based on the inherited class.
For example:
Podcast extends Model ....
There are some functions like this that needs to be called statically and dynamically.
for example:
$podcastList = Podcast::findAll($db);
I get all podcasts objects from DB without need to have a podcast object instanciated.
But i can also do:
$podcast = new Podcast($db)
$podcastList = $podcast->findAll(); //no db here.... passed before
$db is a class i wrote to make operation on Database. IT simply does with OOP, what mysql_* do with functions. I'm not using PDO, i may use in future, but now i use mysql_* :P
that are the incriminated functions
public static function findAll($db=NULL, $self=NULL) {
if($self == NULL) {
$self = new static($db);
} else {
$self = $this;
}
$self->tableName = "";
$self->db = NULL;
$is_static = !(isset($this) && get_class($this) == __CLASS__);
if($is_static) {
//die(__CLASS__ . "::" . __FUNCTION__ . " CALLED STATICALLY");
if(!$self->db) {
die(__CLASS__ . "::" . __FUNCTION__ . " CALLED STATICALLY AND DB IS NULL");
//It stops here!
}
$self->tableName = $self->genTableName();
} else {
$self->db = $this->db;
$self->tableName = $this->tableName;
}
$query = "SELECT * FROM {$self->tableName}";
$r = $self->db->exec($query);
if(!$r) {
die(__CLASS__ . ":Error " . __FUNCTION__ . " record: " . $self->db->getError());
}
if($self->db->countRows($r) == 0) {
return NULL;
}
$objects = array();
while($row = $self->db->fetch($r, DBF::FETCH_ASSOC)) {
$objectClass = __CLASS__;
$object = new $objectClass($this->db);
//TODO Do it dinamically indipendently of column name
$f = get_class_vars($objectClass);
foreach ($f as $field => $value) {
$chuncks = explode("_", $field);
if($chuncks[0] == "f") {
$object->{$field} = $row[$chuncks[2]];
}
}
$objects[] = $object;
}
return $objects;
}
public function __call($name, $arguments) {
if ($name === 'findAll'){
return static::findAll($arguments, $this);
}
}
Both are part of a class.
Thank you for the help !
There's a lot wrong with this code. More important than your many logic mistakes (why are you setting $self = $this, then $self->db = NULL, then $self->db = $this->db?) is that you are misunderstanding what it means to be able to call static functions dynamically in PHP. The object $this simply doesn't exist in a static method. The call $podcast->findAll() looks non-static, but it's still static.
To do what you want to do, here are some options:
leave the function static and call findAll($this->db, $tablename) as needed
put the function into the db class and call it with parameter tablename
EDIT:
The second in my list is how I would do it. This is because you already have to have a db object in your original example, and there is nothing in particular that makes the function's purpose only suited to Podcast objects and not to, say, any other object representing database rows.
//calling examples:
$podcastlist = $db->findAll('Podcast');
$podcast = new Podcast($db);
$podcastlist = $podcast->findAll();
public class db {
....
function findAll($classname, $tablename=NULL) {
if(!isset($tablename)) {
//let's pretend you put default table names as class constants
$tablename = get_constant($classname.'::DEFAULT_TABLE');
}
$query = "SELECT * FROM {$tableName}";
$r = $this->exec($query);
if(!$r) {
throw new Exception("Error " . __FUNCTION__ . " record: " . $this->getError());
}
if($this->countRows($r) == 0) {
return NULL;
}
$objects = array();
while($row = $this->fetch($r, DBF::FETCH_ASSOC)) {
$object = new $classname($this);
//the following is an easier way to do your original foreach
foreach($row as $field=>$value) {
if(property_exists($classname, "f_".$field)) {
$object->{'f_'.$field} = $value;
}
}
$objects[] = $object;
}
//something you forgot:
return $objects;
}
}
public class Podcast extends Model {
....
public function findAll($tablename=NULL) {
return $this->db->findAll(class_name($this), $tablename);
}
}
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?
Can we dynamically create and initialize an object in PHP?
This is the normal code:
class MyClass{
var $var1 = null;
var $var2 = null;
.
.
public function __construct($args){
foreach($args as $key => $value)
$this->$key = $value;
}
}
---------------------
$args = ($_SERVER['REQUEST_METHOD'] == "POST") ? $_POST : $_REQUEST;
$obj = new MyClass($args);
The above code works fine. Please note that the names of REQUEST parameters are accurately mapped with the members of class MyClass.
But can we do something like this:
$class = "MyClass";
$obj = new $class;
If we can do like this, then can we initialize $obj by using $args.
According to this post, $obj = $class should work. But it does not work for me. I tried get_class_vars($obj). It threw an exception.
Thanks
It's more a comment, but I leave it here more prominently:
$class = "MyClass";
$obj = new $class($args);
This does work. See newDocs.
You have to overload some other magic methods:
__get (a method that gets called when you call object member)
__set (a method that gets called when you want to set object member)
__isset
__unset
Please see this codepad to see your code rewritten to work with what you want:
<?php
class MyClass{
var $properties = array();
public function __construct($args){
$this->properties = $args;
}
public function __get($name) {
echo "Getting '$name'\n";
if (array_key_exists($name, $this->properties)) {
return $this->properties[$name];
}
return null;
}
}
$args = array("key1" => "value1", "key2" => "value2");
$class = "MyClass";
$obj = new $class($args);
echo "key1:". $obj->key1;
?>
You can use Reflection to instanciate an object with parameters.
<?php
class Foo {
protected $_foo;
protected $_bar;
public function __construct($foo, $bar)
{
$this->_foo = $foo;
$this->_bar = $bar;
}
public function run()
{
echo $this->_foo . ' ' . $this->_bar . PHP_EOL;
}
}
$objectClass = 'Foo';
$args = array('Hello', 'World');
$objectReflection = new ReflectionClass($objectClass);
$object = $objectReflection->newInstanceArgs($args);
$object->run();
See Reflection on php manual.
The scenario is this
class a
{
public $val;
}
class b extends a
{
}
class c extends b
{
}
$one = new b();
$one->val = "a value";
$other = new c();
echo $other->val;
// wanted 'a value', got ''
So the result i need here is: "a value", but of course is blank.
What i need is that the 'a' class to always be used as an instance in 'b'. So whenever i use a class that extends the 'b', the parent 'a' class to be inhereted as an instance.
If you read the php manual on the static keyword it gives an example of exactly what you are trying to do. You can read about it here: http://www.php.net/manual/en/language.oop5.static.php
Here is the example code they use.
<?php
class Foo
{
public static $my_static = 'foo';
public function staticValue() {
return self::$my_static;
}
}
class Bar extends Foo
{
public function fooStatic() {
return parent::$my_static;
}
}
print Foo::$my_static . "\n";
$foo = new Foo();
print $foo->staticValue() . "\n";
print $foo->my_static . "\n"; // Undefined "Property" my_static
print $foo::$my_static . "\n";
$classname = 'Foo';
print $classname::$my_static . "\n"; // As of PHP 5.3.0
print Bar::$my_static . "\n";
$bar = new Bar();
print $bar->fooStatic() . "\n";
?>
Since $other = new c(); is actually creating a new instance, it is not possible.
but if you declare val as Static member, you will have the result that you want.
<?
class a
{
public static $val;
}
class b extends a
{
}
class c extends b
{
}
$one = new b();
a::$val = "a value";
echo c::$val;
Here is how to do it without Inheritance:
class A
{
public $foo;
}
class B {
public function __construct(A $a)
{
$this->a = $a;
}
}
class C {
public function __construct(A $a)
{
$this->a = $a;
}
}
$a = new A;
$b = new B($a);
$c = new C($a);
$b->a->val = 'one value';
echo $c->a->val;
If you dont like having to fetch $a first to get to val, you could assign by reference
class A
{
public $foo;
}
class B {
public function __construct(A $a)
{
$this->val = &$a->val;
}
}
class C {
public function __construct(A $a)
{
$this->val = &$a->val;
}
}
$a = new A;
$b = new B($a);
$c = new C($a);
$b->val = 'one value';
echo $c->val;
Though personally I find the first approach more maintainable and clear.