implement function as object in PHP - php

Is it possible to implement functions as object instances in PHP? I'm used to doing this in Java with the code below, but I can't seem to find a similar approach in PHP. Is it possible?
interface OneVarFunction {
public int eval(int x);
}
static void routine() {
OneVarFunction func1 = new OneVarFunction() {
public Boolean eval(int x) {
return x*x;
}
};
OneVarFunction func2 = new OneVarFunction() {
public Boolean eval(int x) {
return 2*x+1;
}
};
}

It is possible in PHP7+
in your case, an example would be
interface OneVarFunction {
public function eval($x);
}
//...
$test = new class implements OneVarFunction {
public function eval($x) {
return $x*$x;
}
};
For more information, see the corresponding site of the PHP Manual, which also provides further examples.
It is not possible in versions prior to PHP7, though.

Related

PHP How to use decompression after decryption using Decorator Pattern?

For studying purposes I was trying to create a GoF Decorator implementation using as example a possibility to convert a text to compressed text or encrypted text.
<?php
interface DataSource {
public function gerar($texto): string;
public function recuperar($texto) : string;
}
class TextoBase implements DataSource {
public function gerar($texto): string {
return $texto;
}
public function recuperar($texto) : string {
return $texto;
}
}
abstract class Decorator implements DataSource {
private DataSource $decorado;
public function __construct(DataSource $decorado) {
$this->decorado = $decorado;
}
public function gerar($texto): string {
return $this->decorado->gerar($texto);
}
public function recuperar($texto) : string {
return $this->decorado->recuperar($texto);
}
}
class CriptoDecorator extends Decorator {
const KEY = 'vDIa5JdknBqfrKOu8d7UpddnBMCH1vza';
const NONCE = 'Ra5LeH7ntW2rvkz3dmqI5Stx';
public function gerar($texto): string {
return $this->encrypt(parent::gerar($texto));
}
public function recuperar($texto): string {
return $this->decrypt(parent::recuperar($texto));
}
public function encrypt($data) {
return sodium_crypto_secretbox($data, self::NONCE, self::KEY);
}
private function decrypt(string $data): string {
return sodium_crypto_secretbox_open($data, self::NONCE, self::KEY);
}
}
class CompressaoDecorator extends Decorator {
const NIVEL_COMPRESSAO = 6;
public function gerar($texto): string {
return $this->comprimir(parent::gerar($texto));
}
public function recuperar($texto): string {
return $this->descomprimir(parent::recuperar($texto));
}
private function comprimir(string $stringData): string {
return gzcompress($stringData, self::NIVEL_COMPRESSAO);
}
private function descomprimir(string $stringData): string {
return gzuncompress($stringData);
}
}
$texto = "olá mundo !";
$decorado = new CompressaoDecorator(new CriptoDecorator(new TextoBase()));
$texto_decorado = $decorado->gerar($texto);
echo PHP_EOL;
echo $decorado->recuperar($texto_decorado);
For some reason I'm got warning:
Warning: gzuncompress(): data error in C:\wamp64\www\curso\designer_patterns\estrutural\decorator\real_life.php on line 93
So, Is there a way to fix this and allow Both Decorators to be stacked and be used to gerar(generate) and recuperar(retrieve) ?
Thanks in advance
You need to unwind in the same order that you setup. If you compress then encrypt, you need to decrypt and then uncompress.
The fast fix for this specific code is to change your recuperar method in CompressaoDecorator
class CompressaoDecorator extends Decorator
{
public function recuperar($texto): string
{
return parent::recuperar($this->descomprimir($texto));
}
}
If you want to solve this in the abstract, I would handle this with a factory instead that can guarantee order. To do that, I don't think the individual objects themselves should concern themselves with parent, the factory should do the job of chaining things.
Edit
Actually, as I think about this more, you don't need the factory, you just need to swap your order for all of your recuperar methods, so this one would change, too:
class CriptoDecorator extends Decorator
{
public function recuperar($texto): string
{
return parent::recuperar($this->decrypt($texto));
}
}
This should allow you to call either encrypt or compress first, and as long as you use the same chain the reverse should work, too.

When passing classes by the service and when use type hinting

Which version of my example code is better and correct object-oriented?
1)
class ServiceA
{
private $serviceB;
public function __construct(ServiceB $serviceB)
{
$this->serviceB = $serviceB;
}
public function first() : int
{
return 1 + $this->serviceB->second();
}
}
class ServiceB
{
public function second() : int
{
return 2;
}
}
2)
class ServiceA
{
private $serviceB;
public function __construct($serviceB)
{
$this->serviceB = $serviceB;
}
public function first() : int
{
return 1 + $this->serviceB->second();
}
}
class ServiceB
{
public function second() : int
{
return 2;
}
}
This is without type-hinting in constructor, because if the class has to be versatile and easy to change should not be there type-hinting.
3)
class ServiceA
{
private $serviceB;
public function __construct()
{
$this->serviceB = new ServiceB();
}
public function first() : int
{
return 1 + $this->serviceB->second();
}
}
class ServiceB
{
public function second() : int
{
return 2;
}
}
Because I want to always use ServiceB in this class. But does not that break the law of Demeter?
4)
class ServiceA
{
private $serviceB;
public function first() : int
{
$this->serviceB = new ServiceB();
return 1 + $this->serviceB->second();
}
}
class ServiceB
{
public function second() : int
{
return 2;
}
}
This is similar to 3. I use ServiceB only there where I want it.
5)
class ServiceA
{
public function first() : int
{
$serviceB = new ServiceB();
return 1 + $serviceB->second();
}
}
class ServiceB
{
public function second() : int
{
return 2;
}
}
The simplest version.
In all of the examples, I mean that in ServiceA I always have to use ServiceB. If I want to change ServiceB to ServiceC then I will also have to change the contents of ServiceA class, so in that case I need to use example 1?
I have separated these classes to preserve the principle of single responsibility and they always have to work together. In addition, ServiceB I use elsewhere.
Your code needs to tell exactly what it's doing to avoid confusion and misinterpretation. So it should version be 5).
This example is not good because it reads as "A can be configured with an instance of B which is created and configured somewhere else".
Even worse than 1) because it doesn't tell us anything about the constructor parameter. If you want more flexibility you should use an interface.
Reads as "A always needs B and might use it in several places".
Just an example of a bad code. If you want B to be lazily initialized in A you should put into factory method which will tell your intentions clearly.
Reads as "Method first of A needs B" which is exactly what you wanted.
Another possible solution if B is heavy to initialize is to initialize it lazily and store in a property:
/**
* #var B
*/
private $_b
private function getB() : B
{
if (!$this->_b) {
$this->_b = new B();
}
return $this->_b;
}
Also, if A always needs B you might have a look at aggregates from domain-driven design. But it's hard to advise something good here because we don't know much about your project.
My general advice is to write the simplest possible code when you are unsure about your abstractions or relations between different objects. In your question 5) can be easily refactored into 1) or 3) if needed. So at this point there is no need to waste your time on such question. Look at your code as at something which evolves with time. You don't need to provide final solutions with each piece of code you write.

PHP Classes function inside function?

I'm self-studying the PHP language. And I'm focused on the latest PHP OOP language.
I search for some "ready-to-install" PHP software and as I scan for some references to search and know, I saw lines of code with a structure like this (can't remember so I'll create my own):
$myapp->settings->getValue('openforum');
$myapp->settings->setValue('closeformaintenance', '1');
So my question is, how can I reproduce the code above? I don't know what term to use that line of code (objects, I guess?).
Something like this:
$newLogin->search($uid)->setLogin($dateToday);
Like that. I really need to do that way so I can organize my coding structure. Thanks by the way.
And also for the final question, IS THAT POSSIBLE?
Here's a fairly straight forward way of looking at it, using dependency injection.
Try it out: https://3v4l.org/iSJgL
Note, the below requires PHP 7 due to the string type hint. Remove that and I believe it should work in 5.6 just fine.
<?php
$myapp = new MyApp(new SettingsBag([
'works' => false,
'random' => rand(),
]));
var_dump($myapp->settings()->get('random'));
var_dump($myapp->settings()->get('works'));
// Let's change it up...
$myapp->settings()->set('works', true);
// Now it should be true.
var_dump($myapp->settings()->get('works'));
These would normally have namespaces like \App and/or \App\Configuration, but I ignore that here so it's easier to follow:
class MyApp {
private $settings_bag = null;
function __construct(SettingsBag $settings_bag)
{
$this->settings_bag = $settings_bag;
}
public function settings()
{
return $this->settings_bag;
}
}
class SettingsBag {
private $settings = null;
function __construct(array $settings = [])
{
$this->settings = $settings;
}
public function set(string $key, $value)
{
return $this->settings[$key] = $value;
}
public function get(string $key)
{
return $this->settings[$key];
}
}
What you try to achieve is called method chaining. You can get this by the following:
<?php
class TestClass {
private $val = '';
public function test1($val) {
$this->val = $val;
return $this;
}
public function test2() {
echo 'Hello '.$this->val;
}
}
$test->test1('World')->test2(); // Hello World
You have simply to return the instance of the object on the method to allow the method chaining.
You can read more here.
It's method chaining.
See code below:
class T {
public function test() {
// do something
return $this;
}
}
$x = new T;
$x->test()->test();

Inline interface implementation - Implement interface methods at declaration

I come from java, where we can do something like this:
Action.java:
public interface Action {
public void performAction();
}
MainClass.java:
public class MainClass {
public static void main(String[] args) { //program entry point
Action action = new Action() {
public void performAction() {
// custom implementation of the performAction method
}
};
action.performAction(); //will execute the implemented method
}
}
As you can see, I'm not creating a class which implements Action, but I'm implementing the interface directly on declaration.
Is something like this even possible with PHP?
What I've tried:
action.php:
<?php
interface Action {
public function performAction();
}
?>
myactions.php:
include "action.php";
$action = new Action() {
public function performAction() {
//do some stuff
}
};
What I get:
Parse error: syntax error, unexpected '{' in myactions.php on line 3
So, my question is: is something like this possible with PHP? How should I do it?
With PHP 7, this has become possible with anonymous classes.
$action = new class implements Action() {
public function performAction() {
//do some stuff
}
};
No, can't. PHP doesn't offer anonymous classes like Java does. You can however try to simulate the behaviour you want, but the results will be...mixed at best.
Here's some code:
interface Action
{
public function performAction();
}
class MyClass
{
public function methodOne($object)
{
$object->performAction(); // can't call directly - fatal error
// work around
$closure = $object->performAction;
$closure();
}
public function methodTwo(Action $object)
{
$object->performAction();
}
}
$action = new stdClass();
$action->performAction = function() {
echo 'Hello';
};
$test = new MyClass();
$test->methodOne($action); // will work
$test->methodTwo($action); // fatal error - parameter fails type hinting
var_dump(method_exists($action, 'performAction')); // false
var_dump(is_callable(array($action, 'performAction'))); // false
Hope it helps!

Is it possible to write series of statements that repeatedly refer to a single object in PHP?

Is it possible to write series of statements that repeatedly refer to a single object without having to write the object every time?
I came to this because I used to do this in Visual Basic:
With person
.setFullName(.firstName+" "+.lastName)
.addParent(parent)
.save()
End With
This is a shorthand for
person.setFullName(person.firstName+" "+person.lastName)
person.addParent(parent)
person.save()
Is it possible to achieve this in PHP?
To rewrite the following code without having to write $person 5 times?
$person->setFullName($person->firstName.' '.$person->lastName);
$person->addParent($parent);
$person->save();
Note: I'm not referring to methods chaining for 2 reasons:
1) I want to use public members as well
2) I don't work with classes I wrote, so I cannot add return $this; to all the methods
Thanks
There is exists PHP lib that allow to do it:
https://github.com/lisachenko/go-aop-php
Example of implementation:
http://go.aopphp.com/blog/2013/03/19/implementing-fluent-interface-pattern-in-php/
Create your aspect
<?php
use Go\Aop\Aspect;
use Go\Aop\Intercept\MethodInvocation;
use Go\Lang\Annotation\Around;
class FluentInterfaceAspect implements Aspect
{
/**
* Fluent interface advice
*
* #Around("within(FluentInterface+) && execution(public **->set*(*))")
*
* #param MethodInvocation $invocation
* #return mixed|null|object
*/
protected function aroundMethodExecution(MethodInvocation $invocation)
{
$result = $invocation->proceed();
return $result!==null ? $result : $invocation->getThis();
}
}
Add interface for matching
interface FluentInterface
{
}
class User implements FluentInterface
{
protected $name;
protected $surname;
protected $password;
public function setName($name)
{
$this->name = $name;
}
public function setSurname($surname)
{
$this->surname = $surname;
}
public function setPassword($password)
{
if (!$password) {
throw new InvalidArgumentException("Password shouldn't be empty");
}
$this->password = $password;
}
}
Usage
$user = new User;
$user->setName('John')->setSurname('Doe')->setPassword('root');
But you could write your matching rule without adding new interface.
P.S. It's not an proper answer to the question because required other syntax sugar. PHP do not support such syntax.
You can't do it in PHP.
The syntax of the language does not permit it
In PHP you can do this, but of course you can create shorter variable
$p = &$person;
$p->setFullName($p->firstName.' '.$p->lastName);
$p->addParent($parent);
$p->save();
unset($p);
But in this case you still have -> operator and variable and without already mentioned libs you won't get more.
Yes, you can do it. It's called method chaining (if I remember correctly). Let me put you a simple example:
class A {
public $attributes;
public function __construct() {
return $this;
}
public function methodA($a) {
if (!empty($a)) {
$this->attributes["a"] = $a;
}
return $this;
}
public function methodB($b) {
if (!empty($b)) {
$this->attributes["b"] = $b;
}
return $this;
}
public function methodC($c) {
if (!empty($c)) {
$this->attributes["c"] = $c;
}
return $this;
}
}
The key to what you're looking for is to return the object itself (hence, the reference to return $this;) and you get the same behaviour you had with VB. In PHP you would do it like this:
$a = new A();
$a->methodA(5)->methodB(50)->methodC(500);
Or even:
$a = (new A())->methodA(5)->methodB(50)->methodC(500);
Hope that helps :)

Categories