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.
Related
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();
I've got a Validator class and a UserValidator class which extends from it.
My Validator has a public method setRule(...) with public visibility.
When I extend from it I want to change the visibility of the setRule(...) parent method to private/protected within the child so that it's only visible for the child and no outsiders can call this method from the child.
Is that possible? If so, how could I achieve it?
From an architectural point of view this is not recommended. As already stated in the comments the clean way would be to set your method to protected so only children can access it.
I cannot think of a single use case that would put me in the need to call a public method on a parent class but where I am not allowed to call it on the child class.
That's against the Open/Closed principle. Classes should be open for extension, but not for modification.
Since that was not the question I'll provide a way how that can be achieved though. But note:
This method makes use of an extra class which will be responsible for the instantiation
It's a hack. This solution will not make use of PHP's native language features when throwing accessibility errors.
First let's define the classes you already had
<?php
class Validator {
public function setRule()
{
echo "Hello World";
}
}
class UserValidator extends Validator {
public $prop = 'PROPERTY';
}
There's nothing special here. So let's go on and create a custom exception class for the visibility error.
<?php
class MethodNotAccessibleException extends Exception {}
This exception will be thrown when we try to invoke a "pseudo-private" method on the child class.
Now we want to create the Class that will be responsible for instantiating your child class. It is basically just a wrapper that defines a lock property which holds method names that should not be accessible.
<?php
class PrivateInstanceCreator {
protected $reflectionClass;
protected $lock = [];
protected $instance;
public function __construct($classname, $args = [])
{
// We'll store an instance of the reflection class
// and an instance of the real class
$this->reflectionClass = new ReflectionClass($classname);
$this->instance = $this->reflectionClass->newInstanceArgs($args);
return $this;
}
// The lock method is able to make a method on the
// target class "pseudo-private"
public function lock($method)
{
$this->lock[] = $method;
return $this;
}
// Some real magic is going on here
// Remember. This class is a wrapper for the real class
// if a method is invoked we look for the method
// in the real instance and invoke it...
public function __call($method, $args)
{
// ... but as soon as this method is defined as
// locked, we'll raise an exception that the method
// is private
if(in_array($method, $this->lock))
{
$reflectionMethod = $this->reflectionClass->getMethod($method);
if($reflectionMethod->isPublic())
throw new MethodNotAccessibleException('Method: __' . $method . '__ is private and could not be invoked');
}
return call_user_func_array([$this->instance, $method], $args);
}
// The same goes for properties
// But in this case we'll do no protection
public function __get($prop)
{
return $this->instance->{$prop};
}
}
Our final step is the instantiation.
<?php
$userValidator = new PrivateInstanceCreator('UserValidator', []);
$userValidator->lock('setRule');
$userValidator->setRule(); //Will throw an exception
Instead of instantiating the class directly we'll do it by using our custom wrapper class.
Of course you could handle it in the child class itself, but that's a way to accomplish your task without touching the classes directly.
Having said that, it is still a dirty hack whose usage should be avoided if possible. If you would instantiate the child class directly the inherited methods would still be public.
So if a developer has no knowlege about the wrapper class he'll have a hard time to figure out how to instantiate the child class properly.
Update:
To make the child class uninstantiable directly you can set the constructor to private and call newInstanceWithoutConstructor() from the reflection class, which is even dirtier, since that would make Dependency Injection for the class completely impossible. I'm just mentioning it for completenesses sake. Usage is still not recommended
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.
I've been programming in PHP for several years and I've only just recently begun to look at object oriented code. Now I understand classes and such:
class Myclass {
public function __construct() {
}
}
and all that good stuff... I also understand creating functions and calling in my index.php:
$someVar = new Myclass;
One thing I've been trying to understand, being that i've recently looked at codeigniter and I like one thing about it and want to try and accomplish the same thing without actually using codeigniter.
in code igniter they have the variable $this appear to be their class variable. But by using that, you're able to call from multiple classes all at once.. such as:
$this->load->module(); which is in one class file..
$this->db->query(); which is in another class file.
I've searched google for the last few days trying to figure out how to do this same thing where each class would have the correlation between them all allowing me to run $this->class_name->function_name in my projects instead of creating a new variable for each class or for the sake of a clean index file, having every function in a single class file.
Any information (aside from buy this book - as that isn't an option for me) is greatly appreciated and I will thank you now (and will probably thank you again later just for good measure).
I've been reading you and Phil's comments. First off, you can't use $this on index.php. $this can only be used in the context of an object. So you could do,
$someVar = new Myclass;
...
$someVar->db->something();
...instead.
I'm not entirely sure what you mean by "read classes," but you can assign members to MyClass exactly as Phil indicates:
class MyClass {
private $inj;
function __construct(Injected $inj) {
$this->injected = $inj;
}
}
Note that the private $inj declaration is not mandatory, but skipping it is dangerous. Any non-declared members added are automatically public, and this can potentially screw with you if you rely on magical get. I would declare the properties you need.
Finally, you either need to include all class definitions you will use, use a function like load_class(), or use autoloading. If Injected above is not a declared class, you will get an error when trying to create one. load_class() almost certainly includes the class definition somehow.
The load and db references are class properties which are themselves other objects with public module() and query() methods respectively. For example
class MyClass
{
/**
* #var CI_DB
*/
private $db;
/**
* #var Loader
*/
private $load;
public function __construct(CI_DB $db, Loader $load)
{
$this->db = $db;
$this->load = $load;
// PHP also allows you to add arbitrary object properties
// that receive a "public" visibility
// Please note, this is not a good practice
$this->foo = new Foo;
}
public function someMethod()
{
$this->load->module();
$this->db->query();
// You can also use foo even though it is not defined
// in the class properties
$this->foo->something();
}
}
See http://www.php.net/manual/en/language.oop5.properties.php
Adding the foo property like we did is dangerous. Because it receives the public visibility, it may be altered externally to the class.
$class = new MyClass($db, $load);
$class->foo = new Bar;
$class->someMethod(); // will break if Bar does not contain a something() method
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.