PHP Syntax not allowed - php

I would like to know why the syntax below cannot work with PHP. Anyone with an insight perhaps it does not make any sense or something.
($this->getState($state))->getEvent('eventOpen')->attach($observeCallback);
Basically the getState($state) method returns an object that within itself has both getEvent($eventName) and attach($observerCallbackToAttach).
However, this throws an error and doesn't work.
Am I breaking the rules for thinking this is a valid syntax?

Please note that ->attach($observeCallback) runs on the result of ->getEvent('eventOpen') -- not the result of $this->getState($state).
Check what the getEvent() method returns. For this to work it needs return $this;.
Or else, clarify you code as such:
$tmp = $this->getState($state);
$tmp->getEvent('eventOpen');
$tmp->attach($observeCallback);
Or alternatively, move the attach() method to the class used in the object returned by getEvent()

if the getState method returns an object which has 2 methods getEvent and attach then to make this work you have to return the same object with getEvent / attach. When you do getEvent()->attach() you are using the return value of getEvent not getState.

What you want to do to make this work is to return $this in your methods:
class Something
{
function setState($state)
{
if ($state != '') {
$this->state = $state;
}
return $this;
}
function setUberState($uberState)
{
if ($uberState != '') {
$this->uberState = $uberState;
}
return $this;
}
}
Using the above class you should be able to do:
$something = new Something();
$object = $something->setState('state')->setUberState('uberstate');

Related

Fatal error: Uncaught Error: Call to a member function X on Y

I am trying to learn OOP PHP so much of this is new to me. I have seen other posts but havent found one that answers my question.
class Test
{
public function a(){
//getting data...
return $array;
}
public function b($array){
return true;
}
}
$test = new Test();
$x = $test->a()->b();
When I attempt the above I get the following error:
Fatal error: Uncaught Error: Call to a member function a() on array
Can someone explain why this doesnt work? a returns an array and b accepts an array.
In order to do what you're trying to do here, you'd need to use this instead:
$x = $test->b($test->a());
The second arrow in the expression
$x = $test->a()->b();
attempts to call an object method on the return value of $test->a(), which is an array as you know. It does not pass the return value of a() as an argument to b().
In order to use a syntax like ->a()->b(), a() must return an object with a method b(). If the method b() is a method from the same object, you can do that by returning $this in a(), but if it also needs to return an array, that won't work, so you won't be able to chain the methods like this.
It is possible to make it work if a() doesn't return the array, but instead stores in in an object property, and b() doesn't take an array, but instead operates on the data in the property.
class Test
{
protected $data;
public function a() {
//getting data...
$this->data = $theDataYouGot;
return $this;
}
public function b($array) {
// do something with $this->data
return true;
}
}
Personally I try to avoid this sort of thing because I think it adds unnecessary complexity and makes testing more difficult without much added benefit, but I have seen it done.

PHP inherit method which return $this;

I am searching for the correct way to the next code in PHP:
class X {
var $A = array();
function Y() {
$this->A[] = array('price'=>1);
return $this;
}
}
class Y extends X {
var $VAT = 1.27;
function Y() {
parent::Y(); //at this point what is the correct way to call parent method?
foreach ($this->A AS $akey => $aval) {
if (is_array($aval)&&(array_key_exists('price',$aval))) {
$this->A[$akey]['price'] = $aval['price'] * $this->VAT;
}
}
return $this;
}
}
When I call parent method with "parent::Y();" I think this will not the correct way in PHP because it will return with an object which not ordered to any variable identifier and may cause a warning or a notice in error log.
Have anybody a good advice for what is the correct way to call method in this situation - Without modifying class X?
If you need to call parent method you can simply do it without a problem using parent::method_name().
As in this case $A property is public (var used) it will be visible also in child class.
You don't need to worry that method Y returns $this. It's used probably for chaining class methods and you don't use it here so you don't need to care about it.
As far as the official documentation goes, parent::method(); is the way to go.
The method is fine as it is. No need to assign the result of parent::Y() to a variable.

Fatal error: Can't use method return value in write context in <filename> on line <ifconditioin statement>

I get the error for the following code
class Myclass {
//...variables
public function getName() {
return $this->strName;
}
public function checkDup() {
if(empty($this->getName())) { //HERE IS THE ERROR
$strMessage = 'Please Enter First Name';
return $strMessage;
}
}
}
$a = new Myclass (); //assume constructor is present and variables are set in class
$a->checkDup();
What could be the solution?
My getName() function returns the name of the variable
I figured out what was going wrong here.
I should be referring to the class member variable using $this and not call the getName() function again inside the class. This changes the function to :
public function checkDup() {
if(empty($this->strName)) { //HERE IS THE SOLUTION
$strMessage = 'Please Enter First Name';
return $strMessage;
}
}
change:
if(empty($this->getName())) {
to
$name = $this->getName();
if( empty($name) ) {
...
empty() only checks variables as anything else will result in a parse error
the empty construct is a bit silly that way. see the manual:
Note:
Prior to PHP 5.5, empty() only supports variables; anything else will
result in a parse error. In other words, the following will not work:
empty(trim($name)). Instead, use trim($name) == false.
I don't like any of the answers here. Yes you can reference $this->strName directly. But what if you can't? What if getName() has some important functionality?
Then the only option is to create another variable? $var = $this->getName();.
That also sucks.
Generically whenever I access a class property or function dynamically I enclose it in braces {} so:
I'll know it's dynamic.
I'll get meaningful errors if there are any.
Examples:
$this->{$variable};
$this->{$class->property};
$this->{$class->method()};
$this->{function()};
$this->{$array['index']};

Chained PHP controls

I'm making a form validation class and it works like this currently.
$validator->setVar($_POST['Username'])
->standardFilter(array('XSS', 'SQL_INJECTION'))
->customRegex()
->replace('This', 'With this')
->getResult();
While it works perfectly when chained like this, I can't archieve the following result.
$validator->setVar($_POST['Username'])
->isValidEmail()
->isValidPhoneNumber()
->isSet()
->isNull()
->getResult()
For example, script returns the following values
->isValidEmail() (true)
->isValidPhoneNumber() (true)
->isSet() (false)
Basically, I'm going to make an array, fill it with true/false depending on the result of each function, and I'll look for a specific value in array (a false). If it exists, the class will return false regardless of the rest of the chains. (or I can just override variables, not important here.)
However, I want $validator to stop chaining once it gets a false from a function. Let's say it received a false from isSet(). It shouldn't execute isNull() and getResult() since we already have a failed check.
How can I archieve this in PHP?
TL;DR:
var_dump($validator->setVar('Test message')->isInteger()->setTrue());
//false //true
Output: false, because once isInteger() failed, rest of the chain isn't executed.
How can I archieve this in PHP?
Nothing like good source code to learn from. I would suggest exploring the Zend Framework's Validation classes. It provides the same chaining functionality you describe.
...More source code check isValid() specifically.
Try something like this
class FooBar
{
private $SomethingWrong = false;
function Bar()
{
if( $this->SomethingWrong )
throw new Exception('SomeThing is wrong');
return $this;
}
function Foo()
{
return $this
}
}
$foobar = new FooBar();
$foobar->Bar()
->Foo();
The Foo() part will not be executed, because of the exception in the Bar().
Of course, there are some variations. If you do not want a exception, but a silent non-execute, you could try this:
class FooBar
{
private $SomethingWrong = false;
function Bar()
{
$this->SomethingWrong = true;
return $this;
}
function Foo()
{
if( !$this->SomethingWrong ) {
// do my stuff
}
return $this
}
}
The only way to do this, in any language, is to throw an exception. You can't return the validator object (which is necessary for chaining) and also return true or false, all while having the chaining work. That said, I am not advocating the use of exceptions in this manner. I am in complete agreement with vascowhite's comments below.
Rather than have it stop in the middle of the chain, why not consider the isSet, isNull, etc. methods as instructions to tell the validator what to check. Then have a validate method called at the end of the chain. The validate method can perform the validation based on the validator state (as set by the other methods). And that validate method can also return a true or a false, or a custom state object, with the result of the validation.
Instead of return a value, you can throw a custom exception, which abort the code execution.
Add an try-catch block to the code, handle your exception and everything works fine.
EDIT:
What you also can do is a little bit magic and not really to be recommed. But nice to know, this is possible in php, so better use Exceptions
class PassThroughValidator extends ...
{
private $val;
public function __construct($result)
{
$this->val = $result;
}
public function __call($name, $arguments)
{
return $this;
}
public function getResult()
{
return $this->val;
}
}
class EmailValidator extends ...
{
function isMail()
{
if (...) {
// do something here
return $this;
}
// set Result to false or something similar
return new PassThroughValidator($this->getResult());
}
}
Considering that the value returned in each step of the chain is an object, you can not have one of the chained methods return true/false. it must always return an object instance. So I guess what you would need to do is add some property on the object to indicate that validations should not be done, and if the property is set, just ignore the validation attempt and return the object as is.
So perhaps something like this in simplified form, showing only one such validation:
class validator {
protected $ignore_validations = false;
protected $value = null;
protected $is_null;
public function isNull () {
if(true === $this->ignore_validations) {
return $this;
} else if(is_null($this->value)) {
$this->is_null = true;
$this->ignore_validations = true;
return $this;
} else {
$this->is_null = false;
return $this;
}
}
}

PHP object method doesn't behave as I expect

I can't quite understand why the output of this code is '1'.
My guess is that php is not behaving like most other OO languages that I'm used to, in that the arrays that php uses must not be objects. Changing the array that is returned by the class does not change the array within the class. How would I get the class to return an array which I can edit (and has the same address as the one within the class)?
<?php
class Test
{
public $arr;
public function __construct()
{
$this->arr = array();
}
public function addToArr($i)
{
$this->arr[] = $i;
}
public function getArr()
{
return $this->arr;
}
}
$t = new Test();
$data = 5;
$t->addToArr($data);
$tobj_arr = $t->getArr();
unset($tobj_arr[0]);
$tobj_arr_fresh = $t->getArr();
echo count($tobj_arr_fresh);
?>
EDIT: I expected the output to be 0
You have to return the array by reference. That way, php returns a reference to the array, in stead of a copy.
<?php
class Test
{
public $arr;
public function __construct()
{
$this->arr = array();
}
public function addToArr($i)
{
$this->arr[] = $i;
}
public function & getArr() //Returning by reference here
{
return $this->arr;
}
}
$t = new Test();
$data = 5;
$t->addToArr($data);
$tobj_arr = &$t->getArr(); //Reference binding here
unset($tobj_arr[0]);
$tobj_arr_fresh = $t->getArr();
echo count($tobj_arr_fresh);
?>
This returns 0.
From the returning references subpage:
Unlike parameter passing, here you have to use & in both places - to
indicate that you want to return by reference, not a copy, and to
indicate that reference binding, rather than usual assignment, should
be done
Note that although this gets the job done, question is if it is a good practice. By changing class members outside of the class itself, it can become very difficult to track the application.
Because array are passed by "copy on write" by default, getArr() should return by reference:
public function &getArr()
{
return $this->arr;
}
[snip]
$tobj_arr = &$t->getArr();
For arrays that are object, use ArrayObject. Extending ArrayObject is probably better in your case.
When you unset($tobj_arr[0]); you are passing the return value of the function call, and not the actual property of the object.
When you call the function again, you get a fresh copy of the object's property which has yet to be modified since you added 5 to it.
Since the property itself is public, try changing:
unset($tobj_arr[0]);
To: unset($t->arr[0]);
And see if that gives you the result you are looking for.
You are getting "1" because you are asking PHP how many elements are in the array by using count. Remove count and use print_r($tobj_arr_fresh)

Categories