If you have something like the following:
abstract class User {
function checkThis() {
return true;
}
function mainFunction() {
}
}
and you want to call checkThis() from within mainFunction(), would you do it like this?
abstract class User {
function checkThis() {
return true;
}
function mainFunction() {
if ($this->checkThis())
echo "Works";
}
I seem to be having problems if I call this from within another class, say:
class SecondClass {
function test() {
User::mainFunction();
}
}
Provides this error:
Fatal error: Call to undefined method SecondClass::checkThis()
You should maybe consider having a class you can instantiate which extends this abstract class. e.g.
class userConcrete extends User {
}
Then in second class you can inject the user object like so:
class SecondClass{
protected $user;
public function __construct(userConcrete $user)
{
$this->user = $user;
}
function test(){
$this->user->mainFunction();
}
}
Also making mainFunction public in your abstract class.
Related
The magical __call() and __callStatic can pretty much handle any non existing method on the class, but is there a way to handle a non existing magical method on a class?!
Here's an example on why I need this:
I have a class called DoSomething:
class DoSomething{
public function ok(){
echo 'Something!';
}
}
I want to call this class as a function for a reason! which should call the __invoke function of that class:
$doSomething = new DoSomething();
$doSomething();
Normally by doing that, the class should look for the __invoke function, however in my case I don't to have that function declared on my class (DoSomething), instead I want to be able to call another function (such as the ok()) if the __invoke doesn't exist.
I was expecting something like this to work, but of course it didn't :)
public function __call($class, $arguments)
{
$object = IoC::resolve($class);
$object->ok(...$arguments);
}
The main goal is to use the class as a function, without having to declare the __invoke method. Handle the function does not exist error and call another function instead.
I think that would be really cool :D I appreciate suggestions or other solutions to achieve this.
Internal solution
Extract an abstract class
You could extract an abstract class and have your classes extend it:
<?php
abstract class Invokable
{
public function __invoke()
{
return $this->ok();
}
abstract public function ok();
}
class DoSomething extends Invokable
{
public function ok()
{
echo 'Something';
}
}
$doSomething = new DoSomething();
echo $doSomething();
For an example, see:
https://3v4l.org/m0ih8
Extract a trait
You could extract a trait and have your classes use it:
<?php
trait InvokableTrait
{
public function __invoke()
{
return $this->ok();
}
}
class DoSomething
{
use InvokableTrait;
public function ok()
{
echo 'Something';
}
}
$doSomething = new DoSomething();
echo $doSomething();
For an example, see:
https://3v4l.org/ftUfI
External Solution
Create a proxy
You could create a proxy (a decorator) that composes the object that is not invokable:
<?php
class InvokableDecorator
{
private $decorated;
public function __construct($decorated)
{
$this->decorated = $decorated;
}
public function __call($name, $arguments)
{
/**
* delegate to decorated object if the method exists
*/
if (method_exists($this->decorated, $name)) {
return $this->decorated->{$name}($arguments);
}
}
public function __invoke()
{
return $this->decorated->ok();
}
}
class DoSomething
{
public function ok()
{
echo 'Something';
}
}
$doSomething = new InvokableDecorator(new DoSomething());
echo $doSomething();
For an example, see:
https://3v4l.org/C3XEX
Create a handler
You could create a handler that takes care of determining this externally:
<?php
class Handler
{
public function handle($subject)
{
if (is_callable($subject)) {
return $subject();
}
if (method_exists($subject, 'ok')) {
return $subject->ok();
}
throw new \BadMethodCallException(sprintf(
'Unable to handle instance of "%s"',
get_class($subject)
));
}
}
class DoSomething
{
public function ok()
{
echo 'Something';
}
}
$handler = new Handler();
echo $handler->handle(new DoSomething());
For an example, see:
https://3v4l.org/E0NVs
I have the simplest bit of code :
Interface
interface iCrudRepository{
public function Create($id);
public function Read($id);
public function Update($id);
public function Delete($id);
}
Parent
class Repository
{
function __construct()
{
echo "SHOULD NOT BE CALLED AUTOMATICALLY";
}
}
Class
require_once(__DIR__.'/../injection/bootstrap.php');
class Admin extends Repository implements iCrudRepository
{
function Create($id)
{
}
function Read($id)
{
}
function Update($id)
{
}
function Delete($id)
{
}
}
$admin = new Admin();
$admin->Create("Something");
The bootstrap class autoloads my classes via the spl_autoload_register function. Since in the Admin class I don't call the parent constructor, it shouldn't execute what is in the parent's constructor right?
The Output
SHOULD NOT BE CALLED AUTOMATICALLY
Probably missing something obvious here but can't quite figure out why it is called.
Docs state:
Parent constructors are not called implicitly if the child class
defines a constructor.
So you have to do this in order to prevent what you are seeing:
class Admin extends Repository implements iCrudRepository
{
public function __construct()
{
}
function Create($id)
{
}
function Read($id)
{
}
function Update($id)
{
}
function Delete($id)
{
}
}
I have a code:
<?php
abstract class Model
{
static protected $_table;
static public function setTable()
{
self::$_table = get_called_class();
}
static public function getTable()
{
if(!isset(self::$_table)) {
self::setTable();
}
return self::$_table;
}
}
class User extends Model {}
class Post extends Model {}
echo User::getTable();
echo "<br>";
echo Post::getTable();
?>
The output of echoing it, is: "User User". I can't understand it why value of property one's class go to another. Why doesn't second echo give 'Post' output? What am I getting wrong?
Because you are using static properties, after Model::$_table gets set the first time your class isn't going to set it again. Unless you change your Model::getTable() function so that it calls self::setTable() every time.
You could also create Model as a trait instead of a traditional class.
For example:
trait class Model
{
static protected $_table;
static public function setTable()
{
self::$_table = get_called_class();
}
static public function getTable()
{
if(!isset(self::$_table)) {
self::setTable();
}
return self::$_table;
}
}
class User {
use Model;
}
class Post {
use Model;
}
echo User::getTable();
echo "<br>";
echo Post::getTable();
How do you access a child method eg.?
class A
{
public function Start()
{
// Somehow call Run method on the B class that is inheriting this class
}
}
class B extends A
{
public function Run()
{
...
}
}
$b = new B();
$b->Start(); // Which then should call Run method
Class A should not try to call any methods that it itself does not define. This will work just fine for your scenario:
class A {
public function Start() {
$this->Run();
}
}
However, it will fail terribly should you actually do this:
$a = new A;
$a->Start();
What you're trying to do here sounds very much like a use case for abstract classes:
abstract class A {
public function Start() {
$this->Run();
}
abstract function Run();
}
class B extends A {
public function Run() {
...
}
}
The abstract declaration will precisely prevent you from shooting your own foot by trying to instantiate and Start A without extending and defining required methods.
If B is inherited from A then B will be like:
class B extends A
{
public function Start()
{
...
}
public function Run()
{
...
}
}
So as Run() and Start() are in the same class, we can call Run() in Start() directly.
public function Start()
{
Run();
}
Suppose we have a class. We create an object from the class and when we do the class Extends himself base on the object initialization value..
For example:
$objectType1 = new Types(1);
$objectType1->Activate(); // It calls an activation function for type 1
$objectType2 = new Types(2);
$objectType2->Activate(); // It calls an activation function for type 2
I don't want to use the standard procedure of class extending:
class type1 extends types{}
You cannot extend a class at runtime. Use an instance variable to distinct the two type or use a factory.
Example for instance variable:
class Types() {
private $type;
public function __construct($type) {
$this->type = $type;
}
public function activate() {
if($this->$type == 1) {
// do this
}
else if($this->type == 2) {
// do that
}
}
}
Example for factory pattern:
abstract class BaseClass {
// Force Extending class to define this method
abstract public function activate();
// Common method
public function printOut() {
echo "Hello World";
}
}
class Type1 extends BaseClass {
public function activate() {
// do something
}
}
class Type2 extends BaseClass {
public function activate() {
// do something else
}
}
class TypeFactory {
public static function getType($tpye) {
if($type == 1) {
return new Type1();
}
else if($type == 2) {
return new Type2();
}
}
}
then you do:
$obj = TypeFactory::getType($1);
$obj->activate();
Update:
Since PHP 5.3 you can use anonymous functions. Maybe you can make use of this.