Understanding parameters passed to abstract function - php

I was just going through the code of this observer pattern HERE, and i came across the below line of code:
abstract class AbstractObserver {
abstract function update(AbstractSubject $subject_in);
}
The very first function in that snippet actually , now i am very new to PHP, I know javascript , but i am not so good in PHP , now what on earth are these parameters passed to the abstract function:
AbstractSubject $subject_in
?? What is this ?

Its a single parameter that it's typed, meaning that that function can only recieve an instance of AbstractSubject as the parameter.
Note that the words are not separated by a comma, but a space, meaning that the first word (AbstractSubject) defines the type of the parameter (second word, $subject_in) the method may receive, if you pass a value of any other type than an instance of AbstractSubject, you will get an exception raised.
So, an implementation of the given method should look something like this:
class MyObserver extends AbstractObserver
{
public function update(AbstractSubject $subject_in)
{
//Your implementation of the method goes here.
}
}

Related

How do I get the function name outside a function in PHP?

Is this possible?
Pseudo-code:
class MyClass
{
function myFunc1()
{
...
}
function myFunc2()
{
echo GET_FUNCTION_NAME($this->myFunc1)
}
}
Wanted output:
myFunc1
In the code above the GET_FUNCTION_NAME method/function/construct/whatever would give back the textual representation of the function name given as parameter.
So the main point would be to get the name of a function as a string from outside the function.
All the code I have found deals with giving a function name via a string (eg. specifying callback methods), but none of them mentions how to get that function name without manually writing it in a string (thus duplicating code in a string and making refactoring harder than needed).
OTOH from inside the function it is easy with eg. __FUNCTION__ variable, so I'm not looking for that.
EDIT
A typical use case would be any callback method.
One example where I confronted this problem is the set_error_handler() method where it awaits a callable as first parameter. The callable can be simplified as a string. The problem is that if I specify the function name as a string, any time in the future when I will do refactoring I will have to take extra care to search for the strings as well and do special handling of them otherwise wrong references will be left there.
Not to mention the principle that any name should be defined once and any other use should refer to that one.
If the problem is that You need to specify a callback not using a string, but the function symbol itself, You can do with a help of anonymous function:
class MyClass {
function call(callable $c) {
...
}
function mycallback() {
...
}
function dosomejob() {
$this->call(function() { $this->mycallback(); })
}
}
From point of view of Your refactoring tool, there's still call to function mycallback, it's not reffered as a string.

Is there a way to explicitely ignore agruments declared in function signature

Sometimes, especially with callbacks functions or inheritance/implementation case, I don't want to use some arguments in method. But they are required by the method interface signature (and I can't change the signature, let's say it's something required via Composer). Example:
// Assuming the class implements an interface with this method:
// public function doSomething($usefull1, $usefull2, $usefull3);
public function doSomething($usefull, $useless_here, $useless_here) {
return something_with($usefull);
}
// ...
In some other languages (let's say Rust), I can ignore these arguments explicitly, which make the code (and intention) more readable. In PHP, it could be this:
public function doSomething($usefull, $_, $_) {
return something_with($usefull);
}
Is this possible in PHP? Did I missed something?
Side note: it's not only for trailing arguments, it could be anywhere in the function declaration
I think the best you can hope for is to give them unique names that will suggest that they will not be used in the call.
Perhaps:
function doSomething($usefull,$x1,$x2){
return something_with($usefull);
}
Or:
function doSomething($ignore1,$useful,$ignore2){
return something_with($useful);
}
PHP wants to have arguments accounted for and uniquely named.
Edit: If you want to avoid declaring variables that you won't use (but you know they are being sent), try func_get_args() and list(). This should make the code lean, clean, readable. (Demo)
function test(){
// get only use argument 2
list(,$useful,)=func_get_args();
echo $useful;
}
test('one','two','three'); // outputs: two
Assign default value for optional parameter.
function doSomething($usefull,$useless1=null,$useless2=null){
return something_with($usefull);
}
Now....
Parameter 1 is required
Parameter 2 is optional
Parameter 3 is optional
Call function like..
doSomething($data);
doSomething($data,$anotherData);
doSomething($data,$anotherData,$anotherData1);
Your concrete object does not fit the interface completly, so you can just add a adapter class between them. So the interface stay as it is and your object just get what it really need.
class Adapter extends CustomInterface
{
function doSomething($ignore1,$useful,$ignore2){
return $customClass->something_with($useful);
}
}

class name in method along with variable

I am reading about design patterns in PHP and I keep seeing the following syntax, for example
abstract class AbstractObserver {
abstract function update(AbstractSubject $subject_in);
}
or
class PatternObserver extends AbstractObserver {
public function __construct() {
}
public function update(AbstractSubject $subject) {
}
}
(code is part of this example)
where "AbstractSubject" is another abstract class.
I am used to defining methods like methodName($var), not including a class name in there, like methodName(className $var).
So, what actually the class name does in a method ? My best guess is that it passes something like a reference in that class? Can you explain to me what it actually does?
Thanks
It's called Type Hinting, since php 7 you can use scalar types to type hint parameters. (Some more)

PHP - override function with different number of parameters

I'm extending a class, but in some scenarios I'm overriding a method. Sometimes in 2 parameters, sometimes in 3, sometimes without parameters.
Unfortunately I'm getting a PHP warning.
My minimum verifiable example:
http://pastebin.com/6MqUX9Ui
<?php
class first {
public function something($param1) {
return 'first-'.$param1;
}
}
class second extends first {
public function something($param1, $param2) {
return 'second params=('.$param1.','.$param2.')';
}
}
// Strict standards: Declaration of second::something() should be compatible with that of first::something() in /home/szymon/webs/wildcard/www/source/public/override.php on line 13
$myClass = new Second();
var_dump( $myClass->something(123,456) );
I'm getting PHP error/warning/info:
How can I prevent errors like this?
you can redefine methods easily adding new arguments, it's only needs that the new arguments are optional (have a default value in your signature). See below:
class Parent
{
protected function test($var1) {
echo($var1);
}
}
class Child extends Parent
{
protected function test($var1, $var2 = null) {
echo($var1);
echo($var1);
}
}
For more detail, check out the link: http://php.net/manual/en/language.oop5.abstract.php
Another solution (a bit "dirtier") is to declare your methods with no argument at all, and in your methods to use the func_get_args() function to retrieve your arguments...
http://www.php.net/manual/en/function.func-get-args.php
As of PHP 8.1, there's a cool hack to override a class's method with extra number of required arguments. You should use the new new in initializers feature. But how?
We define a class having a constructor always throwing a ArgumentCountError, and make it the default value of every extra required parameter (an improved version of #jose.serapicos's answer). Simple and cool!
Now let's see it in action. First, we define RequiredParam:
final class RequiredParameter extends \ArgumentCountError
{
public function __construct()
{
// Nested hack
throw $this;
}
}
And then:
class Base
{
public function something(string $baseParam): string
{
return $baseParam;
}
}
class Derived extends Base
{
public function something(
string $baseParam,
string|RequiredParameter $extraParam = new RequiredParameter(),
): string {
return "$baseParam + $extraParam";
}
}
This way, no one can bypass the extra parameters, because RequiredParameter is declared as final. It works for interfaces as well.
How Good or Bad is This?
One advantage is that it's a little more flexible than setting default parameters as null, as you can pass the constructor of RequiredParameter an arbitrary list of parameters and probably build a custom error message.
Another advantage is that it's handled less manually, and thus being more safe. You may forget about handling a null value, but RequiredParameter class handles things for you.
One major disadvantage of this method is that it breaks the rules. First and foremost, you must ask yourself why you would need this, because it breaks polymorphism in most cases. Use it with caution.
However, there are valid use cases for this, like extending parent class's method with the same name (if you cannot modify the parent, otherwise I recommend you to use traits instead), and using the child class as standalone (i.e. without the help of parent class's type).
Another disadvantage is that it requires you to use union types for each parameter. While the following workaround is possible, but it requires you to create more classes, which may hurt understandability of your code, as well as having little impact on maintainability and performance (based on your conditions). BTW, no hack comes for free.
Eliminating the use of Union Type
You could extend from or implement RequiredParameter the compatible type of the actual parameter to be able to remove the need for union type:
class BaseRequiredParameter extends Base
{
public function __construct()
{
throw new \ArgumentCountError();
}
}
class Derived extends Base
{
public function something(
string $baseParam,
Base $extraParam = new BaseRequiredParameter()
): string {
return "$baseParam + {$extraParam->something()}";
}
}
It's also possible for strings, if you implement the Stringable interface (e.g. Throwable implements it by default). It doesn't work for some primitive types including bool, int, float, callable, array, etc., however, if you're interested, you're still able to use some alternatives like Closure or Traversable.
For making your life easier, you may want to define the constructor as a trait and use it (I'm aware of this answer, but in fact, this is a valid useful case for a constructor in a trait, at least IMO).
Your interface/abstract class or the most parent class, should cotantin the maximum number of params a method could recieve, you can declare them explicitely to NULL, so if they are not given, no error will occur i.e.
Class A{
public function smth($param1, $param2='', $param3='')
Class B extends A {
public function smth($param1, $param2, $param3='')
Class C extends B {
public function smth($param1, $param2, $param3);
In this case, using the method smth() as an object of 'A' you will be obligated to use only one param ($param1), but using the same method as object 'B' you will be oblgiated to use 2 params ($param1, $param2) and instanciating it from C you have to give all the params

Restrict type of method parameter with two or more class names?

We can restrict type of method parameters; for example, we should say that function parameter should be an instance of object described in class with name "Some Class".
function some_function(Some_Class $object) {
}
Is there any php native posibilities to restrict method parameter with two or more classes? For examle, "Some Class" or "Some Class2" or "Some Class3".
Or maybe there is any way to restrict method parameter with classes which implements interface with name "Some_Interface"?
Thank you.
You can do it with an interface, e.g.
interface LoggableInterface
{
public function log($message);
}
Some classes implementing the interface
class FileLog implements LoggableInterface {
public function log() { /* code to log to File ... */ }
}
class DbLog implements LoggableInterface {
public function log() { /* code to log to Db ... */ }
}
class SysLog implements LoggableInterface {
public function log() { /* code to log to SysLog ... */ }
}
Then you can use it as a TypeHint like this:
function some_function(LoggableInterface $anyLogger);
This way you make sure the param passed to some_function() has a method log(). It doesn't matter which concrete you pass to it (FileLog, DbLog or SysLog), but just that these classes implement the interface.
You should use class inheritance or interfaces to do that.
In principle not, but you can fake it: since PHP is a dynamic language, type errors happen at runtime; and you can manually trigger an error by adding something like this at the start of your function:
if(check_any_type_constraints_here)
trigger_error("Argument is not valid!", E_USER_ERROR);
In order to crash the script, it will work as reliably as PHP's built-in parameter type-checking ;).
You just need to ensure that, if you add an actual constraint on the method parameter list, all valid values will be able to go through it (you don't need to ensure all invalid values will fail the check, that's what the manual check is for). For OR'ing types, the safest way to achieve this is to not declare the type in the header, and fully rely on the manual check. If you ever want to AND types (like if you want a value that implements two or more specific interfaces), then you can put either on the header (preferably the one most likely to fail), and check the other(s) on the body.
Hope this helps.

Categories