Static method that calls itself on an object - php

I want to have a class that i can use it this way:
Thing::doThis()->doThat()->doImportantThing();
OR
Thing::doThat()->doImportantThing();
OR
Thing::doImportantThing();
But currently i can only use it this way:
$thing = new Thing();
$thing->doThis()->doThat()->doImportantThing();
What do i have to change in the class so i can use it the way i want? I already return a Thing instance in every function call.
I want to use that for a simple reason, imagine a mail class, in the constructor you define a default from and to, but you might want to change it, so you do Mail::setFrom()->send(). If you want to change the to, you use Mail::setTo()->send(). It just makes it easier to use if it's going to be used in different projects by different people.
I want by calling Mail::{something} to have like a constructor call and then run the {something} function.

You can do this
class Thing {
public static function __callStatic($name, $arguments){
$thing = new self;
return $thing->$name($arguments);
}
public function __call($name, $arguments){
return $this->$name($arguments);
}
private function doThis(){
echo 'this'.PHP_EOL;
return $this;
}
private function doThat(){
echo 'that'.PHP_EOL;
return $this;
}
private function doImportantThing(){
echo 'Important'.PHP_EOL;
return $this;
}
}
Thing::doThis()->doThat();
Thing::doThat()->doImportantThing();
It is a really ugly work-around, though. And it disables you to have private methods.
DEMO

One great thing for static methods is that they can work in object context, and can be called like this: $instance->staticMethod()
Here it is (even you get code completion in ide, and works as axpected as you want):
class Mail
{
public static $from;
public static $to;
public static $subject;
public static $message;
protected static $onlyInstance;
protected function __construct ()
{
// disable creation of public instances
}
protected static function getself()
{
if (static::$onlyInstance === null)
{
static::$onlyInstance = new Mail;
}
return static::$onlyInstance;
}
/**
* set from
* #param string $var
* #return \Mail
*/
public static function from($var)
{
static::$from = $var;
return static::getself();
}
/**
* set to
* #param string $var
* #return \Mail
*/
public static function to($var)
{
static::$to = $var;
return static::getself();
}
/**
* set subject
* #param string $var
* #return \Mail
*/
public static function subject($var)
{
static::$subject = $var;
return static::getself();
}
/**
* set message
* #param string $var
* #return \Mail
*/
public static function message($var)
{
static::$message = $var;
return static::getself();
}
public static function send()
{
echo "<pre><b>Hurrah mail sent</b>"
. "\nFrom:\t ".static::$from.""
. "\nTo:\t ".static::$to." "
. "\nSubject: ".static::$subject.""
. "\nMessage: ".static::$message;
echo "</pre>";
}
}
Example usage:
Mail::from('george#garcha')
->to('michel#tome')
->subject('hehe works')
->message('your welcome')
->send();
Output
Hurrah mail sent
From: george#garcha
To: michel#tome
Subject: hehe works
Message: your welcome
Example 2 (this also works):
Mail::from('george#garcha')
->to('michel#tome');
Mail::subject('hehe works')
->message('your welcome')
->send();

Related

json_encode empty with no error [duplicate]

This question already has answers here:
PHP class instance to JSON
(5 answers)
Closed 4 years ago.
I got an object. I need to turn into JSON for storage but when I try to encode it into JSON it returns an empty JSON object. When I tried to use json_last_error.
The code I used
echo $payload["sub"];
echo json_encode($user);
echo json_last_error_msg();
The result I get
"102573480781696194937{}No error".
The User class I'm trying to encode
<?php
/**
* Created by PhpStorm.
* User: Student
* Date: 13-4-2018
* Time: 10:40
*/
namespace php;
class User
{
private $isAdmin = false;
private $registeredFood = array();
private $googleID;
private $name;
private $notes = array();
private $email;
/**
* User constructor.
* #param $googleID
*/
public function __construct($googleID)
{
$this->googleID = $googleID;
}
/**
* #return mixed
*/
public function getGoogleID()
{
return $this->googleID;
}
/**
* #return bool
*/
public function isAdmin()
{
return $this->isAdmin;
}
/**
* #param bool $isAdmin
*/
public function setIsAdmin($isAdmin)
{
$this->isAdmin = $isAdmin;
}
/**
* #return array
*/
public function getRegisteredFood()
{
return $this->registeredFood;
}
/**
* #param array $registeredFood
*/
public function setRegisteredFood($registeredFood)
{
$this->registeredFood = $registeredFood;
}
/**
* #return mixed
*/
public function getName()
{
return $this->name;
}
/**
* #param mixed $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* #return array
*/
public function getNotes()
{
return $this->notes;
}
/**
* #param array $notes
*/
public function setNotes($notes)
{
$this->notes = $notes;
}
/**
* #return mixed
*/
public function getEmail()
{
return $this->email;
}
/**
* #param mixed $email
*/
public function setEmail($email)
{
$this->email = $email;
}
}
?>
I hope someone can help me
It is because your class's properties are private.
An example class with only private properties ...
php > class Foo { private $bar = 42; }
php > $obj = new Foo();
do not expose values:
php > echo json_encode($obj);
{}
But an example class with public properties ...
php > class Bar { public $foo = 42; }
php > $objBar = new Bar();
do it!
php > echo json_encode($objBar);
{"foo":42}
\JsonSerializable
PHP provide an'interafce \JsonSerializable that require a method jsonSerialize. This method is automatically called by json_encode().
class JsonClass implements JsonSerialize {
private $bar;
public function __construct($bar) {
$this->bar = $bar;
}
public function jsonSerialize() {
return [
'foo' => $this->bar,
];
}
}
I prefer this solution because is not good to expose publicly properties
serialization and unserialization ...
If you need to serialize and unserialize php object you can ...
php > class Classe { public $pub = "bar"; }
php > $obj = new Classe();
php > $serialized = serialize($obj);
php > $original = unserialize($serialized);
php > var_dump($original);
php shell code:1:
class Classe#2 (1) {
public $pub =>
string(3) "bar"
}
$serialized variable contains O:6:"Classe":1:{s:3:"pub";s:3:"bar";}. As you can see is not a json, but is a format that allow you to recreate original object using unserialize function.
You have a couple of options here.
Option 1: Make your class properties public
Like what sensorario mentioned, change the visibility of your properties so that it is accessible from outside the class, which is where you are calling json_encode.
Option 2: Introduce a method/function within the class to return the encoded JSON object
Have a toJson() function inside your User class.
Of course, there are way more options - such as extending User so that User is not "contaminated", etc.
But yup, the general problem is your private properties.

Setting subject variable in Laravel mailables

I have created a mailable php artisan make:mail SendInEmail
class SendInEmail extends Mailable
{
use Queueable, SerializesModels;
public $email;
public $sub;
public $emailcontent;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($email, $sub, $emailcontent)
{
$this->email = $email;
$this->sub = $sub;
$this->emailcontent = $emailcontent;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->subject($sub)->view('emails.sendemail');
}
}
In the build function I am passing the $sub variable, which comes from the controller, but it gives me an error:
Undefined variable: sub
When I use this:
return $this->subject('Some subject')->view('emails.sendemail');
It works fine.
P.S I did some research and found that I need use function to pass the subject variable (some anonymous function magic) (Not sure how to do that with mailables)
You're using the wrong variable, so change it to $this->sub:
return $this->subject($this->sub)->view('emails.sendemail');

Most efficient way of accessing a private variable of another class?

There are many methods around that allow you to access private variables of another class, however what is the most efficient way?
For example:
I have this class with some details in:
class something{
private $details =
['password' => 'stackoverflow',];
}
In another class I need to access them, example (although this obviously wouldn't work since the variable isn't in scope to this class):
class accessSomething{
public function getSomething(){
print($something->details['password']);
}
}
Would a function like this be good enough within the class "something" to be used by the access class?:
public function getSomething($x, $y){
print $this->$x['$y'];
}
you should be using proper getters/setters in your classes to allow access to otherwise restricted data.
for example
A class
class AClass {
private $member_1;
private $member_2;
/**
* #return mixed
*/
public function getMember1() {
return $this->member_1;
}
/**
* #param mixed $member_1
*/
public function setMember1( $member_1 ) {
$this->member_1 = $member_1;
}
/**
* #return mixed
*/
public function getMember2() {
return $this->member_2;
}
/**
* #param mixed $member_2
*/
public function setMember2( $member_2 ) {
$this->member_2 = $member_2;
}
}
which is then called as follows:
$newClass = new AClass();
echo $newClass->getMember1();
echo $newClass->getMember2();

PHP classes and functions/ undefined variable

Why do I get undefined property Takeover::user2 on function takeover?
I'm not sure what I'm doing wrong. Can someone help?
I can call user2->addsaldo() on main file but I can't call it inside another function. Why?
Class user
class User {
/**
* #AttributeType int
*/
private $iduser;
/**
* #AttributeType float
*/
private $saldo=0;
/**
* #AssociationType Portefolio
* #AssociationKind Composition
*/
public $idportefolio;
public function __construct($iduser){
$this->iduser = $iduser;
}
/**
* #access public
*/
public function getid() {
// Not yet implemented
}
/**
* #access public
*/
public function addsaldo($saldo) {
$this->saldo = $saldo;
}
}
Class takeover
class Takeover {
/**
* #AttributeType int
*/
private $idTakeover;
/**
* #AssociationType root
* #AssociationMultiplicity 1
*/
public $Root;
public $IdeasTakerover=array();
public function __construct($idTakeover){
$this->idTakeover = $idTakeover;
}
/**
* #access public
*/
public function GetIdCompraRoot() {
// Not yet implemented
}
public function AddIdeasTakeover($idTakeover, $idideia) {
$this->idTakeover = $idTakeover;
$this->idideia = $idideia;
array_push($this->IdeasTakerover,$idideia);
}
/**
* #access public
*/
public function Takeover() {
$this->user2->addsaldo(200); //USER2 DOES EXIST
}
}
Creating users and calling them:
$takeover = new Takeover(1);
for ($i=0; $i<$conta; $i++ ){
$takeover->AddIdeasTakeover(1,$idsideias[$i]);
}
$takeover->Takeover();
if ($partial == "user") {
$booleanUser = TRUE;
$iduser=substr($buffer, 4);
${'user'.$iduser} = new User($iduser);
}
The problem is not in this class. The problem is that $GLOBALS['user2'] is not defined when referenced here: $GLOBALS['user'.$this->IdeiasTakeover[$i]]. You then call addsaldo() on an undefined array element in $GLOBALS.
On another note, it is impossible to write good code using $GLOBALS. Global variables are bad news. You should not be using/referencing global variables. The exception would be at a low level when referencing $_POST, $_GET, etc. Even still, all the good PHP frameworks wrap these in a request object.
Edit
Dependency Injection is a better way for one class to use another:
class X {
$yInstance;
public function __construct($yInstance)
{
$this->yInstance = $yInstance;
}
public function x()
{
//Call your 'y' method on an instance of Y
$this->yInstance->y();
}
}
class Y {
public function y()
{
echo 'Y::y() called!';
}
}
Call X::x()
$y = new Y();
$x = new X($y);
$x->x();
Output:
Y::y() called!
The easiest way to do this is to use a dependency injection container. Here is my favorite one for PHP: http://symfony.com/doc/current/components/dependency_injection/introduction.html
Also, check out Martin Fowlers classic article about IOC:
http://martinfowler.com/articles/injection.html
Good luck!

PHP: Method Chain with new self()?

I have an object created within a method, and I would like to further process it in another method of the same class.
I tried it like this, but $obj is not passed through to method two():
class SomeClass {
public static function one($id)
{
$obj = new self();
$obj->id = $id;
//...
return $obj;
}
public function two()
{
$obj->id = 2;
return $obj;
}
}
$obj = SomeClass::one($id)->two();
Is there a way to achieve this?
I found this thread How to chain method on a newly created object?, but it's still not quite clear whether this is possible or not.
two is a static method. You're trying to invoke it on an instance, and static methods by definition don't work on a specific instance.
Make the method not static, and manipulate $this instead of $obj.
If I'm not misunderstanding what you're trying to do, if you don't make the second method static, you can return an object and it'll be passed in as $this in the chained call;
class SomeClass {
public $id = 0;
public static function one($id)
{
$obj = new self(); // Create and return new object
$obj->id = $id;
return $obj;
}
public function two()
{
$this->id = 3; // The new object is $this here
return $this;
}
}
$obj = SomeClass::one(5)->two();
Method chaining only makes sense when you are using setters.
In combination with PHPDoc most IDE's (like NetBeans) will support code completion/autocomplete feature again.
p.s note that method chaining can give your more chance on errors like PHP Fatal error: Call to a member function .... on a non-object in .... when mixing in more classes with returning
class Example {
protected $var = null;
public function __construct() {
}
public function __destruct() {
unset($this->var); // explicit memory clearing
}
/**
* #return \Example
*/
public static function create() {
return new self();
}
/**
* #return \Example
*/
public static function getInstance() {
return self::create();
}
/**
* #return \Example
*/
public static function newInstance() {
return self::create();
}
/**
*
* #param mixed $var
* #return \Example
*/
public function setThing1($var) {
$this->var = $var;
return $this;
}
/**
*
* #param mixed $var
* #return \Example
*/
public function setThing2($var) {
$this->var = $var;
return $this;
}
}
Example::create()->setThing1(1)->setThing2('2');

Categories