Can I specify a non strict method requirement for child classes? - php

I have a base class in which I want to specify the methods a child class must have, but not implement them itself. However, the methods in a child class may have a different number of paramaters to the definition in the base class.
Having tried this with an abstract method, php doesn't allow this. Is it possible?

The child class's function can add extra, optional arguments to the signature without it causing errors:
abstract class Foo {
abstract function bar($a);
}
class NewFoo extends Foo {
function bar($a, $b = null) {
//do something
}
}

Short of specifying the abstract method with no parameters and requiring the subclassed method to access the args through func_get_args, I don't see how this would be possible.

I would say this is one of the weak points of PHP's object orientation, that it wasn't designed to handle this kind of use case. It just wasn't meant to allow overloaded methods for its
It is indeed possible to do what you're talking about as a kind of hack, in both the way mentioned above with:
func_get_args()
or, just (like the commenter mentioned) pass in an array of arguments. Alternately you could pass in an object that has your arguments as data members. Then you could extend the parameter/argument object for your child method.
The point is that PHP is a language that thrives on permissiveness and not restriction. Abstract classes have a very basic implementation in PHP. If you have the need for a lot of structure like this, then PHP really might not be the best language choice.

I don't think this is an answer that you will want to use in production as it will be fairly slow, but just for the sake of it I tried to write something using Reflection, which seems to work. You will still get an E_STRICT because method declarations in subclasses are apparently supposed to match.
class a {
protected $requiredMethodsInSubclass = array( 'method1', 'method2', 'method3' );
public function __construct() {
$reflObject = new ReflectionObject($this);
$className = $reflObject->getName();
if ($className == __CLASS__) {
//this class is being instanciated directly , so don't worry about any subclasses
return;
}
foreach ($this->requiredMethodsInSubclass as $methodName) {
try {
$reflMethod = $reflObject->getMethod($methodName);
} catch (ReflectionException $e) { //method not anywhere
trigger_error("Method $methodName is not declared in class " . __CLASS__ . " or subclass $className", E_USER_ERROR);
continue;
}
$declaringClass = $reflMethod->getDeclaringClass();
if ($declaringClass->getName() == __CLASS__) {
//method is declared in this class, not subclass
trigger_error("Method $methodName is not declared in subclass $className", E_USER_ERROR);
}
}
}
public function method1() {
}
public function method2($a) {
}
}
class b extends a {
public function __construct() {
parent::__construct();
//some stuff
}
public function method2($a, $b, $c) {
}
}
$b = new b();

Related

php oop - force static method's param to be object of current class

I want to do something like this:
class myclass{
public static function(__class__ $param){
// do somthing
}
}
but __class__ and self::class and nor static is not working.
how should I do this
If you want to enforce this dynamically for subclasses, I'm afraid that's not possible. The best you can do in this case is something like this:
class myclass {
public static function doStuff(self $a) {
if (!$a instanceof static) {
throw new InvalidArgumentException(sprintf('First argument must be of type %s', static::class));
}
// Do things with $a
}
}
Just use self:
class A
{
public function foo(self $arg)
{
var_dump($arg);
}
}
$a = new A();
$a->foo($a); // object(A)#1 (0) { }
No but, guys, suppose the class is extended tho, he might want to make sure the call to this method uses the child class, not the parent
You can manually restrict this contract for child classes, as shown in other anwsers (instanceof, etc), but it violates the Liskov substitution principle.
A subclass should always satisfy the contract of the superclass. In good design you should not to narrow the type of arguments in overridden methods.
Widening is allowed: Contravariant method argument type and PHP 7.2 partially supports it.
What you're asking does not make that much sense in strongly typed languages so I don't think it is something you can do in PHP.
Consider this:
abstract class A {
public abstract function a(A $myTypeObject);
}
class B extends A {
public function a(B $myTypeObject) {
return $this;
}
}
Now the problem with this code is that it cannot exist because the overridden function must match the same signature as the parent function. In strongly typed languages a would in fact be an overload so B would have 2 declarations of a , one which accepts A and one which accepts B. However in PHP you'll just get a parse error. If you really want to enforce things you need runtime checking:
abstract class A {
public function a($myTypeObject) {
if (!($myTypeObject instanceof static)) {
throw new \Exception("Invalid type");
}
}
}

Regulating write access to object properties based on context

class SomeObject {
protected $foo,
$bar;
protected $context;
public function __construct($context) {
$this->context = $context;
}
public function setFoo($val) {
if ($this->context == 'public') {
throw new \Exception('It is impossible to modify foo property in public context!');
}
$this->foo = $val;
}
public function setBar($val) {
if ($this->context == 'api') {
throw new \Exception('It is impossible to modify bar property in API context!');
}
$this->bar = $val;
}
}
As you can see from this piece of "code" - object restricts setters depending on context value. This code is really hard to maintain. How can we rewrite it to make it beautiful and easy maintainable?
My thoughts are:
Make $context an object(s) implementing interface
isAllowed($object, $propertyName).
After making $context an object we have to thing about how can we store "restrictions" in $context object taking in mind there are a lot of different objects similar to SomeObject.
In every setter I should check $this->context->isAllowed($this, 'foo') - it looks not good. So, probably we want to add some "proxy" over SomeObject?
Passing $context to constructor also seems rather ugly for me.
What's your ideas about it?
Just two general observations:
You may want to segregate your classes into two parts: an immutable base class and a mutable extension:
class Foo {
protected $bar, $baz;
}
class MutableFoo extends Foo {
public function setBar($bar) {
$this->bar = $bar;
}
..
}
This easily solves the problem when the context is defined at object instantiation time and won't ever change. Instead of instantiating with a different context which determines the mutability, you simply instantiate a mutable or immutable version of the class.
If you still need more runtime checks, maybe simply using assertions is the best way to simplify the code:
public function setBar($bar) {
$this->assertCanSet('bar');
$this->bar = $bar;
}
protected function assertCanSet($property) {
if (!/* can set $property */) {
throw new Exception("Cannot set property $property");
}
}
Maybe on the construct, fill a list of restricted methods.
so, for instance :
class SomeObject {
protected $foo,
$bar;
protected $context;
protected $restrictedMethods;
public function __construct($context) {
$this->context = $context;
if($this->context == 'public') {
$this->restrictedMethods['setFoo'] = true;
} else if ($this->context == 'api') {
$this->restrictedMethods['setBar'] = true;
}
}
public function setFoo($val) {
if ($this->isRestricted('setFoo')) {
throw new \Exception('It is impossible to modify foo property in '.$this->context.' context!');
}
$this->foo = $val;
}
public function setBar($val) {
if ($this->isRestricted('setFoo')) {
throw new \Exception('It is impossible to modify bar property in '.$this->context.' context!');
}
$this->bar = $val;
}
protected function isRestricted($methodName) {
return array_key_exists($methodName, $this->restrictedMethods);
}
}
If you are trying to write good OOP, then "Interface Segregation" from the SOLID principle may be useful to you.
interface IBase
{
public function doMethod1();
public function doMethod2();
public function doMethod3();
}
interface IFoo extends IBase
{
public function setFoo($val);
}
interface IBar extends IBase
{
public function setBar($val);
}
function doWork(IBase $obj, $val)
{
$obj->doMethod1();
$obj->doMethod2();
$obj->doMethod3();
if ($obj instanceof IFoo) {
$obj->setFoo($val);
}
if ($obj instanceof IBar) {
$obj->setBar($val);
}
}
I doubt this example is exactly what you need, but I will use it to explain the basic idea.
A class should only have a "Single Responsibility". What that responsibility encompasses can vary however, so in general it is best to limit a class's functionality to a single area of concern as best you can.
If you want to follow "Liskov substitution", then throwing exceptions like that in your functions simply because the "context" was irrelevant, violates this principle.
Enter "Interface segregation":
By implementing an interface, you are (to a certain extent) guaranteeing to the caller of the implemented methods, that those methods will work. By excluding them, you are telling the caller that those methods don't exist.
In the example, the doWork function expects an instance of IBase, and safely calls the methods of that interface. After that, it runs introspection of the object to determine if other "applicable" methods are available.
The goal behind interface segregation is to limit the amount of unneeded features a class is forced to implement, so for you, if the context is public, it shouldn't need the setFoo method.
A clean solution would be to have an ObjectFactory class that creates different objects based on a $context parameter, and having two separate classes (with a common base class) that allows writing to the appropriate properties.
Please find below a possible implementation for your schema:
/**
* Base class that allows subclasses to define which properties are
* writable via setters. Subclasses must not add public setters,
* otherwise the mechanism within this class will not work; subclasses
* can add protected setters, though
*/
class PropertyRestricter {
// only properties listed here are writable
// to be initialised by subclasses
protected $writableProperties;
public function __construct() {
// default implementation allows no writable properties
$this->writableProperties = array();
}
public function __call($method, $arguments) {
$matches = false;
// check if a setter was called, extract the property name
// there needs to be at least one argument to the setter
if(count($arguments) && preg_match('/^set([A-Z][a-zA-Z0-9_]+)$/',$matches)) {
$propName = $matches[1];
$propName[0] = strtolower($propName[0]);
// update the property with the given value
// or throw an exception if the property is not writable
if(is_array($this->writableProperties) && in_array($propName, $this->writableProperties)) {
$this->{$propName} = $arguments[0];
} else {
throw new Exception(get_class() . ": $propName is not writable");
}
} else {
// not a setter, nor a public method
// maybe display a user error
}
}
}
/**
* Common properties for the actual classes
*/
class BaseObject extends PropertyRestricter {
protected $foo, $bar;
}
class PublicObject extends BaseObject {
public function __construct() {
parent::__construct();
$this->writableProperties = array('foo');
}
}
class APIObject extends BaseObject {
public function __construct() {
parent::__construct();
$this->writableProperties = array('bar');
}
}
class ObjectFactory {
public function createObject($context) {
switch($context) {
case 'public': return new PublicObject();
case 'api': return new APIObject();
default: return null;
}
}
}
The root of the objects is the PropertyRestricter class that allows subclasses to define which properties are writable. It makes use of the magic method __call() in order to be able to intercept setter calls and to validate the attempt to write to the property. However please note that this works only if subclasses don't add public setters for their properties.
The next level is the BaseObject class, which only defines the two properties, in order to reduce code redundancy.
The last level contains the two classes that get instantiated by the ObjectFactory: PublicObject, 'APIObject. These classes simply initialise thewritablePropertiesarray, as the rest of the work is done by thePropertyRestricter` class.
This is also a scalable solution, as it allows adding as many properties and subclasses as needed, each subclass defining its property writing rules.
Also the property update within the __call() method can be customised, I implemented it in the simplest way by directly setting the property. Actual setters can be used in subclasses and __call() can be updated to call the setters, with the mention that the setters need to be protected in order for the mechanism to work.

PHP - dynamically extend parent class with static methods

consider the following:
class A
{
public static function bark()
{ echo 'woof'; }
}
class B extends A
{
public static function speak()
{ echo 'hello'; }
}
A::speak();
// Fatal error: Call to undefined method A::speak()
How is one supposed to extend a class with methods that you need to be globally available within that class with methods that are not yet known, but are loaded at run-time, depending on the flow of your application?
Yes sure we can make traits and put use in the class like:
trait B
{
public static function speak()
{ echo 'hello'; }
}
class A
{
use B;
public static function bark()
{ echo 'woof'; }
}
A::speak();
// hello
but then use B is not called dynamically, hence you will have to update class A with every new trait available - manually.
This is absurd, why force developers to break their brain in trying to accomplish something so fundamentally simple?
Does anyone have an idea how this can be done in a clean way? I mean I have seen some impressive methods by using Singletons, namespaces, callbacks and the works, but in each case it requires a lot more code and repetitive programming than what is really needed.
Either that or i'm missing the boat completely haha!
Thanks in advance, your help will be appreciated and voted generously.
I think with some creativity you could make use of the __call magic method.
You could do something like this:
class A
{
/**
* #var array
*/
protected $methods = [];
public function __call($name, $arguments)
{
if (!empty($this->methods[$name]) && is_callable($this->methods[$name])) {
return call_user_func_array($this->methods[$name], $arguments);
}
}
public function addMethod($name, Closure $method)
{
$this->methods[$name] = $method;
}
}
// get class instance (A have no methods except of addMethod)
$instance = new A();
// add methods on runtime
$instance->addMethod('sum', function($num1, $num2) {
return $num1 + $num2;
});
$instance->addMethod('sub', function($num1, $num2) {
return $num1 - $num2;
});
// use methods exactly the same way as implemented fixed on class
echo $instance->sum(2, 2);
echo $instance->sub(3, 2);
Of course you could use also __callStatic for static methods. And if you want to get it a bit more complex also could use the concept of Dependency Injection to add objects instead of methods. Then search the called method through the injected objects and call it when it's found.
I hope this give you at least a good idea.

Blocking the possibility to create classes directly bypassing a factory

In a base class for all the models in our MVC system, I created a factory method BaseCLass::getNew() that returns an instance of the requested child class when called via SomeChildClass::getNew().
Now, I'm looking for a way to force the programmer to use this factory. I.e., idially I'd like that any class created directly, like this:
new SomeChildClass
will throw an exception upon creation, and only classes created by the factory will be usable.
Any ideas how can this be achieved?
Our code is written in PHP, but good chance that your idea will be valuable even if you think on a different language.
edit: I cannot make my constructor private, as the framework constructor in the class that I inherit is public, and php would not allow me this.
By making the constructor of the child class protected. The parent class will have access to all protected methods of the child. Any attempt to directly create the child (ie: new child) will cause a fatal error.
<?php
class factory
{
static public function create()
{
return new child;
}
}
class child extends factory
{
protected function __construct()
{
echo 'Ok';
}
}
$c = factory::create(); // Ok
$c2 = new child; // fatal error
?>
Though this method won't let you throw an exception instead :(
If then absolutely necessary, only debug_backtrace() function comes to mind (besides using singleton for the child itself, or forced object pool patterns using and passing GUID's generated by factory and verified by child). Within the child constructor, look at the 2nd array value to make sure "function" === "create" and "class" === "factory. Throw exception if not matching. I didn't suggest this initially, only because I suspect using debug_backtrace may give a performance hit.
By making the class have a private constructor.
Update -- solution that covers your stated requirements
class Base {
private static $constructorToken = null;
protected static function getConstructorToken() {
if (self::$constructorToken === null) {
self::$constructorToken = new stdClass;
}
return self::$constructorToken;
}
}
class Derived extends Base {
public function __construct($token) {
if ($token !== parent::getConstructorToken()) {
die ("Attempted to construct manually");
}
}
public static function makeMeOne() {
return new Derived(parent::getConstructorToken());
}
}
This solution takes advantage of the object equality rules for stdClass by storing a "magic password" object on the base class which only derived classes can access. You can tweak it to taste.
I wouldn't call it horrible like the debug_backtrace idea, but still I have the impression that things should be done differently.
Declare the class's constructor private, and it can only be called from within the class's own methods like getNew().
there are couple of ways to implement it
make parent class private use magic
user magic function __autoload; check the type of class and through error with not allowed message
http://php.net/manual/en/function.is-a.php
The best way is to define constructor of the class private or protected. But if you cannot do it, you can control where an object of the class is created in the constructor:
trait FactoryChecking
{
protected function checkFactory(string $factoryClass): void
{
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
foreach($trace as $traceItem) {
if ($traceItem['class'] == $factoryClass) {
return;
}
}
throw new Exception('Cannot create class ' . static::class . ' outside of factory');
}
}
class ClassA
{
use FactoryChecking;
public function __construct()
{
$this->checkFactory(Factory::class);
}
}
class Factory
{
public function create(): ClassA
{
return new ClassA();
}
}
Details I described in the article "Forbidding of creating objects outside factory in PHP"

How Many Static Methods is Too Many For One Class?

UPDATE: Rephrasing the question to ask, 'are there too many' static methods (I realize that right now there are only 4 but I originally started with 2) in this class structure? If so, any suggestions on how to refactor these classes to use some sort of Finder class so that I can remove the static functions from the Model classes?
I have the following abstract class:
abstract class LP_Model_Abstract
{
protected static $_collectionClass = 'LP_Model_Collection';
protected $_row = null;
protected $_data = array();
public function __construct($row = null)
{
$this->_row = $row;
}
public function __get($key)
{
if(method_exists($this, '_get' . ucfirst($key)))
{
$method = '_get' . ucfirst($key);
return $this->$method();
}
elseif(isset($this->_row->$key))
{
return $this->_row->$key;
}
else
{
foreach($this->_data as $gateway)
{
if(isset($gateway->$key))
{
return $gateway->$key;
}
}
}
}
public function __set($key, $val)
{
if(method_exists($this, '_set' . ucfirst($key)))
{
$method = '_set' . ucfirst($key);
return $this->$method($val);
}
elseif(isset($this->_row->$key))
{
$this->_row->$key = $val;
return $this->_row->$key;
}
else
{
foreach($this->_data as $gateway)
{
if(isset($this->_data[$gateway]->$key))
{
$this->_data[$gateway]->$key = $val;
return $this->_data[$gateway]->$key;
}
}
}
}
public function __isset($key)
{
return isset($this->_row->$key);
}
public function save()
{
$this->_row->save();
}
abstract public static function get($params);
abstract public static function getCollection($params = null);
abstract public static function create($params);
}
And then this class which provides additional functionality for class table inheritance schemes (where type is important in determining additional functionality in a factory fashion):
abstract class LP_Model_Factory_Abstract extends LP_Model_Abstract
{
protected static $_collectionClass = 'LP_Model_Collection_Factory';
abstract public static function factory($row);
}
These ultimately result in the following type of class declaration:
class Model_Artifact extends LP_Model_Factory_Abstract
{
protected static $_artifactGateway = 'Model_Table_Artifact';
public static function create($params)
{
}
public static function get($params)
{
$gateway = new self::$_artifactGateway();
$row = $gateway->fetchArtifact($params);
return self::factory($row);
}
public static function getCollection($params = null)
{
$gateway = new self::$_artifactGateway();
$rowset = $gateway->fetchArtifacts($params);
$data = array(
'data' => $rowset,
'modelClass' => __CLASS__
);
return new self::$_collectionClass($data);
}
public static function factory($row)
{
$class = 'Model_Artifact_' . $row->fileType;
}
}
When do you know that you have too many static methods in a class? And how would you refactor the existing design so that the static methods are perhaps encapsulated in some sort of Finder class?
I'd have to agree with Brubaker and add that to my thinking it isn't the number of methods so much as the functionality of said methods. If you start thinking that your class has to many methods (static or otherwise) then you might find they can be re-grouped and refactored into a more intuitive architecture.
The first indicator I use when determining if I have to many static methods is if the methods functionality is not stateless. If the static methods change the state of the object they reside in, they probably shouldn't be static.
I agree with BaileyP and I'll add my couple of pennies:
I always work with the idea that a class should have a single reason for existing; it should have one job that it does, and it should do it well. After deciding that, and figuring out what the interface to that class should be, I go through and mark any functions that don't change the state of an instance of the class as static.
If you want to build reusable and testable code, you should avoid static methods altogether. Code which calls static methods (or constructors of non-data-like classes) cannot be tested in isolation.
Yes, you will have to pass around alot more objects if you eliminate static methods. This is not necessarily a bad thing. It forces you to think about the boundaries and cooperation between your components in a disciplined way.
Personally I find that any number of static methods are a sign of trouble. If your class has instance methods and static methods, then most likely you could split the class into two separate entities and change the static methods to instance methods.
Think of a class as a special kind of object, with the distinctive property that it is global by nature. Since it's a global variable, it implies a very strong level of coupling, so you would want to reduce any references to it. Static members will need to be referred, meaning that your code will get a strong level of coupling to the class.
I'll throw in my 2 cents.
First of all, I'll agree that setting some sort of arbitrary limit is not helpful, such as "Once I have more than 10 statics in a class that's too many!". Refactor when it makes sense but don't start doing it just because you've hit some imaginary boundary.
I wouldn't 100% agree with Brubaker's comment about stateful vs. stateless - I think the issue is more about classes vs instances. Because a static method can change the value of another static property which is a stateful change.
So, think of it like this - if the method/property is of or pertaining to the class, then it should probably be static. If the method/property is of or pertaining to an instance of the class, it should not be static.

Categories