PHP: How to get a class member variable from a static method? - php

I am trying to create an abstract Model class that has a static fetchAll method. Subclasses need to specify the name/location that will be used in the fetchAll method. However, I can't figure out how to specify the protected $_name method in a way that is accessible from both the static method and non-static methods. This is what I have so far:
abstract class Model
{
protected $_name;
public static function fetchAll()
{
$request = new ApiRequest();
return $request->get($this->_name);
}
public function save()
{
$request = new ApiRequest();
return $request->put($this->_name, $this->_data);
}
}
class Email extends Model
{
protected $_name = 'zEmailz';
}

Did you consider passing the name as an argument to the fetchAll() method?
class Email extends Model
{
protected $_name = 'zEmailz';
public function getResults()
{
$rows = parent::fetchAll($this->$_name);
}
}
I wouldn't recommend setting the Model::$_name to static, as any possible iterations may override the value and make it difficult to ensure the current value matches what you want. This is one of the many pitfalls of co-mingling static and instantiated members.
-- Update --
You could pass the object into the fetchAll call, sort of (say sort of b/c I never co-mingled DI with static calls) a dependency injection solution:
// Calling code
$email = new Email();
// Do stuff with $email
$results = Model::fetchAll($email);
Then the model class looks like:
abstract class Model
{
public static function fetchAll($object)
{
$request = new ApiRequest();
return $request->get($object->_name);
}
}
-- Update #2 --
Based on your comment you are looking for a method to retrieve rows from the database and hydrate the primary objects so you can reference current values via OO API calls. If I were you would take a look at Doctrine, rather than re-invent the wheel. In Doctrine they have what are known as 'table' classes which are directly related to a model class. For example, you would have an EmailTable.php file, and in this class you would add custom methods to return datasets you wanted.
If you still want to stick with your own way of doing this, then you may want to move the fetchAll method into each child class, otherwise if you keep it in the parent class you are going to end up with a nasty switch/case block for all objects you want to hydrate.
Example (demonstrative only):
class Email extends Model
{
protected $_name = 'zEmailz';
public static function fetchAll()
{
// However you pull rows from DB
while ($row = get_current_row) {
$email = new Email();
$email->setAddress($row['address']);
...
$emails[] = $email;
}
return $emails;
}
}

Just declare the variable as static:
protected static $_name;
And access it using the self or static keyword, depending on whether you want late static binding or not:
return $request->get(static::$_name);

if you want to access your static _name variable from static methods use self::$_name
But it's not a good idea to use static method into base class
Realize, that this method will be proccess only static data (common for all descendants).
So, if you want to access to the all names of descendants, you must add static array of your models names, also you can store params, classname or link to your descendant objects. Then you can access to all descendants or just select one by name or by classname, or by other some id from stored params.

I can be wrong, but if the model is an abstract class, they not have the responsibility to know who is using them. They only specifies that all class that inherit from him, will have a fetchall method, this method can have implementation or not, but he must exists.
If you have a entity that inherits from Abstract Model Class, should be called using the signature Entity::fetchall().
The Entity::fetchall() can internally call the parent::fetchall($name) or similar, with this way, you can isolate the responsibility of who uses whom.

Related

Calling a static parent method while instantiating child class

I'm changing my class structure around to store common database methods in one class. Then extending it from a child class. This should cut down on code but also allows me to overwrite the parent methods when I need to.
I've done the following, for this example I've simplified to the basics compared to the original code which contains more classes.
class parent_object{
private $table_name;
public function all_records(){
$sql = "SELECT * FROM ".$this->table_name;
return $this->execute_sql($sql);
}
}
class child_object extends parent_object{
protected static $table_name="tbl_name";
public function __construct(){
parent::__construct(self::$table_name);
}
}
I want to call the all_records() statically to save myself creating a new object every time.
I'm stuck having to instantiate the child and then call the parent method
$child = new child_object();
$all = $child->all_records();
What I really want to be able to call the parent method statically:
$all = child_object::all_records();
I understand why I can't do it with my code, but would like some way that the child instantiates first then accesses the parent method.
I could write all_records() method in the child_object to instantiate itself and call the parent all_records() but that sort defeats the purpose of extending to cut down on code and the same methods in my child class.
I'm sure its quite simple or some new high level oop function can do it.
Thanks for your help.
The answer is relatively simple, you can turn all your properties into static properties, and then use static:: instead of self::.
http://php.net/manual/en/language.oop5.late-static-bindings.php
Solving your problem this way is considered a bad practice though. Good luck.
You could do something like this:
class child_object extends parent_object
{
protected static $table_name="tbl_name";
public static function factory()
{
return new child_object();
}
public function __construct()
{
parent::__construct(self::$table_name);
}
}
Then when you use it you just do:
$all = child_object::factory()->all_records();

Create a Collection of Objects from a Class Using a Transformer Function

In this question I would like to discuss a problem related to building a collection of homogeneous objects from a class using a transformer function that transforms a passed array or other sort of collection. The problem lies in the fact that I want to be able to see from which class are the objects in a collection when doing the transofrmation and at the same time avoid using statics as we all know they are kind of tricky and the general recommendation is to avoid them.
The scenario is the following:
There is an abstract class that does some common parsing of data (formatting dates, strings, floats, etc.) called AbstractData. Its purpose is to be extended by more concrete classes which make use of the abstract functions and hold the parsed data.
The concrete class uses a mapping array which tells how given raw data has to be parsed using the functions from the abstract class.
Currently what is being done to create a collection of such concrete class objects is the following (take care that the constructor of the Concrete class takes single row of data which it parses automatically using the defined mapping scheme):
collection = [];
foreach($rows as $row) {
collection = new ConcreteClass($row);
}
What I have here basically is just an array of those objects, but I was wondering what would be the best way to keep a more structured collection the same way you could do using generics in Java like List<ConcreteClass> collection = new List<ConcreteClass>(row);
Right now what I did was to make a static "factory" function in the abstract class:
public static function factory($data = null) {
return new static($data);
}
And a function that creates the "processed" collection:
public function createCollectionFromRawData($rows) {
$collection = [];
foreach($rows as $row) {
$collection[] = new static($row);
}
return $collection;
}
And call the concrete class like this: ConcreteClass::factory()->createCollectionFromRawData($rows)
And although it allows for better reading in a way it is a bit redundant since it does not separate concerns and additionally I have to create an empty object of the ConcreteClass just to be able to invoke the non-static createCollectionFromRawData function which I would like to avoid doing.
I was thinking something in the lines of involving DI to solve the problem but I am not really sure what exactly I can do.
I don't see the harm in using the late static binding functions I use them heavily in an ORM i have written but i do record the class name in a var on the class at each level because I have needed it for some tasks. I think you are trying to get a collection of items dependent on what you class you statically give the factory? Here is my crack at solving what I think you are asking. I do this by always using the public method on the abstract class, and defining the protected method on the class you are building as each of these may handle the input differently.
abstract class AbstractData {
protected $_abstractClassData;
public static final function factory($rawData)
{
return static::_createCollectionFromRawData($rawData);
}
}
class ConcreteClass extends AbstractData {
protected $_concreteClassData;
protected static function _createCollectionFromRawData($rows) {
$collection = array();
foreach($rows as $row) {
$collection[] = new static($row); //If you havnt defined a constructor on this class it will use your AbstractData one.
}
return $collection;
}
}
$collection = ConcreteClass::factory($rawData);

Call private method from inherited class

I want to implement a hook-system in my simple ORM, in PHP:
class Record {
public function save() {
if (method_exists($this,"before_save")) {
$this->before_save();
}
//...Storing record etc.
}
}
class Payment extends Record {
private function before_save() {
$this->payed_at = time();
}
}
$payment = new Payment();
$payment->save();
This results in a Fatal Error:
Fatal error: Call to private method Payment::before_save() from
context 'Record' in
Makes sense.
I could change the scope to public, but that seems ugly: no-one but Payment has anything to do with before_save(). It is best left private, IMHO.
How can I make Record call a private method on the class inheriting from the Record?
Add a dummy before_save function to your Record class, set its accessibly to protected. Now all classes that inherit from Record will have this function, if they don't overwrite it it will do NOTHING. If they overwrite it, it can implement the desired functionality.
class Record {
public function save() {
$this->before_save();
//...Storing record etc.
}
protected function before_save() {
return;
}
}
class Payment extends Record {
protected function before_save() {
$this->payed_at = time();
}
}
The winning answer doesn't answer the question. The information about "public", "protected", "private", and "final" should be obtainable on any blog or book.
This question asks about how to use a "private" function from an inherit class. The use case here is you're forced to use 3rd party code that is poorly designed, indiscriminately uses private functions, and faced with having to either find a way to use a private function, or fork the entire repo.
Here is the answer to the question.
class foo {
protected $text = "foo";
private function bar($text)
{
return $text.'->'.$this->text;
}
}
class fooChild extends foo{
protected $text = "bar";
public function barChild()
{
$r = new \ReflectionMethod(parent::class, 'bar');
$r->setAccessible(true);
//return $r->invokeArgs(new foo(), ['output']); // output->foo
return $r->invokeArgs($this, ['output']);//output->bar
}
}
echo (new fooChild())->barChild();
Using the ReflectionMethod class you can call a private method from the inherit class. You can see the difference from using $this and a new instance of the parent. The properties will not be set from the child from a new instance.
Check the error message
Call to private method Payment::before_save() from context 'Record'
This means that you are trying to call a function defined in Payment while you are within Record. Class Record does not have a before_save method because it is further up in the inheritance chain than where the function is defined.
In other words since, the parent-child relation is Record (is parent of) Payment, Payment has access to Records functions (by virtue of inheriting from the parent) but not vice-versa (parent cannot "inherit" child class functions). You can make your function protected which will give it access up and down the inheritance chain, but you might want to rethink the architecture and decide if you want it so.. Ideally you should have the function defined in Record and have it overridden in Payment
Also (and I might be wrong with this), but checking explicitly for method_exists is usually not required unless you are creating a really dynamic system where run time classes can be overlapped and/or generated. If you are defining a class based system from ground-up and you know how you are stitching up the various pieces, usually you would not need to check during run-time if method_exists...just a thought..
change the scope to protected:
http://php.net/manual/en/language.oop5.visibility.php
Visibility and the rules of inheritance in PHP:
Members declared protected can be accessed only within the class itself and by inherited and parent classes
class test {
private function pri($val){
return $val;
}
function caller(){
return $this->pri(5);
}
}
$testobj = new test;
echo $testobj->caller();
You will get 5 as output.
By this way You can access the private function of a class.

Is it a good idea to create a static member in a class object and call that member for specific function

Is it a good idea to create a static member in a class object and call that member for specific function? like:
class Users
{
public static Login(strUsername, strPassword)
{
$objThis = new Users();
....
}
}
and call it like:
Users::Login('admin', 'admin');
or second method:
class Users
{
public Login(strUsername, strPassword)
{
//$objThis = new Users();
....
}
}
and call it like:
$objThis = new Users();
$objThis->Login('admin','admin');
These functions are used when
You don't want to allow, to create
instance of class from outside the
class, indirectly you want to make
constructor private or protected.
Or You want to allow only single instance of class for the whole request(one request). For. eg. Classes for Database, Document etc.
The first method can be useful if you want to restrict access to the class, and not allow it to be instantiated. For example:
class Users {
private function __construct($strUsername, $strPassword) {
// this class can now not be instantiated
// except within itself
}
public static Login($strUsername, $strPassword)
{
return new self($strUsername, $strPassword);
}
}
This forces users of your class to always use the static method to get a User object, which can be desirable if you always want to restrict how its used.
As always, it largely depends on what you want to do. static is like a tool, and you use it when it's the right tool for the job on hand.
Usually static methods should be avoided - they complicate API and refactoring. I using static methods only as alternative to class constructors when initialization may throw an exception (reading from file, etc) and for private utility methods.

When would you need to use late static binding?

After reading this description of late static binding (LSB) I see pretty clearly what is going on. Now, under which sorts of circumstances might that be most useful or needed?
I needed LSB this for the following scenario:
Imagine you're building a "mail processor" daemon that downloads the message from an email server, classifies it, parses it, saves it, and then does something, depending on the type of the message.
Class hierarchy: you have a base Message class, with children "BouncedMessage" and "AcceptedMessage".
Each of the message types has its own way to persist itself on disk. For example, all messages of type BouncedMessage try to save itself as BouncedMessage-id.xml. AcceptedMessage, on the other hand, needs to save itself differently - as AcceptedMessage-timestamp.xml. The important thing here is that the logic for determining the filename pattern is different for different subclasses, but shared for all items within the subclass. That's why it makes sense for it to be in a static method.
Base Message class has an abstract static method (yes, abstract AND static) "save". BouncedMessage implements this method with a concrete static method. Then, inside the class that actually retrieves the message, you can call "::save()"
If you want to learn more about the subject:
http://www.qcodo.com/forums/topic.php/2356
http://community.livejournal.com/php/585907.html
http://bugs.php.net/bug.php?id=42681
One primary need I have for late static binding is for a set of static instance-creation methods.
This DateAndTime class is part of a chronology library that I ported to PHP from Smalltalk/Squeak. Using static instance-creation methods enables creation of instances with a variety of argument types, while keeping parameter checking in the static method so that the consumer of the library is unable to obtain an instance that is not fully valid.
Late static binding is useful in this case so that the implementations of these static instance-creation methods can determine what class was originally targeted by the call. Here is an example of usage:
With LSB:
class DateAndTime {
public static function now() {
$class = static::myClass();
$obj = new $class;
$obj->setSeconds(time());
return $obj;
}
public static function yesterday() {
$class = static::myClass();
$obj = new $class;
$obj->setSeconds(time() - 86400);
return $obj;
}
protected static function myClass () {
return 'DateAndTime';
}
}
class Timestamp extends DateAndTime {
protected static function myClass () {
return 'Timestamp';
}
}
// Usage:
$date = DateAndTime::now();
$timestamp = Timestamp::now();
$date2 = DateAndTime::yesterday();
$timestamp2 = Timestamp::yesterday();
Without late static binding, [as in my current implementation] each class must implement every instance creation method as in this example:
Without LSB:
class DateAndTime {
public static function now($class = 'DateAndTime') {
$obj = new $class;
$obj->setSeconds(time());
return $obj;
}
public static function yesterday($class = 'DateAndTime') {
$obj = new $class;
$obj->setSeconds(time() - 86400);
return $obj;
}
}
class Timestamp extends DateAndTime {
public static function now($class = 'Timestamp') {
return self::now($class);
}
public static function yesterday($class = 'Timestamp') {
return self::yesterday($class);
}
}
As the number of instance-creation methods and class-hierarchy increases the duplication of methods becomes a real pain in the butt. LSB reduces this duplication and allows for much cleaner and more straight-forward implementations.
It's useful when:
You have functionality that varies over the class hierarchy,
The functionality has the same signature over the hierarchy, and
(crucially) You don't have an instance to hang the functionality off of.
If only #1 and #2 obtained, you would use an ordinary instance method. So Alex's problem (see his answer to this question) does not require LSB.
A typical case is object creation, where subclasses create themselves in different ways, but using the same parameters. Obviously you have no instance to call, so the creation method (also known as a factory method) must be static. Yet you want its behavior to vary depending on the subclass, so an ordinary static method is not right. See Adam Franco's answer for an example.
If you need to access an overloaded static property/Method within a method that hasn't been overloaded in a subclass - you need late static binding. A quick example: paste2.org
The classic example is the ActiveRecord class from Rails, if you try to implement something similar in PHP, which would look like this: class User extends ActiveRecord and then try to call User::find(1) the method that gets called is actually ActiveRecord::find() because you haven't overloaded find() in User - but without late static binding the find() method in ActiveRecord has no way of knowing which classed it got called from (self within it will always point to ActiveRecord), and thus it can't fetch your User-object for you.
Suppose you have classes representing tables (row instances) in a simplified object-relational mapper.
You would have a class "User" and a class "Company" who's instances are representing rows of the respective tables.
User and Company would inherit from some base abstract class, let's say "BaseObject" that will have some common methods like save(), delete(), validate() etc ...
If you want to store data about the validation and the table definition, the best place would be in a static variable in each derived class - since the validation and table definition is the same for each instance of User.
Without LSB the mentioned validate() method in BaseObject would have no reference to the static variables defined in User and Company, even though you are calling it through an instance of User. It will look for the same static variable in the BaseObject class, and it will raise an error.
This is my experience with PHP 5.2.8 - LSB is going to be introduced in 5.3
I have a class with a static method that handles some formatting. I have another class that than needs all the functionality of the original one except for how it handles formatting.

Categories