# Allow non-variable arguments to empty()

- Thread: https://externals.io/message/59681
- Original archive: https://news-web.php.net/php.internals/59681
- Started by Nikita Popov on 2012-04-10T22:53:38+00:00
- Messages: 21
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #59681 — Nikita Popov — 2012-04-10T22:53:38+00:00

URL: https://externals.io/message/59681#59681

Hey internals!

Currently the empty() language construct only works on variables. You
can write if (empty($array)) but not empty if (empty(getSomeArray()).

The original reason for this restriction probably is that - in a way -
it "doesn't make sense" to pass anything but a variable to empty() as
you could just use the ! operator in this case. if
(empty(getSomeArray())) is logically equivalent to if
(!getSomeArray()).

I'd like to propose to change empty() to accept arbitrary expressions.

The reason is simple: Even though it is possible to write if
(!getSomeArray()) with the same effect, if (empty(getSomeArray()))
reads much nicer. !getSomeArray() to me somehow implies that
getSomeArray() may return a bool(false) or something like that. On the
other hand empty(getSomeArray()) seems naturally fit for checking for
empty arrays.

Another reason is that currently you get a very obscure error message
if you try to use empty() on a function return value: "Can't use
function return value in write context". Aha. Where did I try to write
to the return value?!

So, what do you think?

Nikita

PS: The patch is trivial: https://gist.github.com/2355274

---

## #59682 — Jelle Zijlstra — 2012-04-10T23:12:59+00:00

URL: https://externals.io/message/59681#59682 · In reply to: #59681

2012/4/10 Nikita Popov <nikita.ppv@googlemail.com>

> Hey internals!
>
> Currently the empty() language construct only works on variables. You
> can write if (empty($array)) but not empty if (empty(getSomeArray()).
>
> The original reason for this restriction probably is that - in a way -
> it "doesn't make sense" to pass anything but a variable to empty() as
> you could just use the ! operator in this case. if
> (empty(getSomeArray())) is logically equivalent to if
> (!getSomeArray()).
>
> I'd like to propose to change empty() to accept arbitrary expressions.
>
> The reason is simple: Even though it is possible to write if
> (!getSomeArray()) with the same effect, if (empty(getSomeArray()))
> reads much nicer. !getSomeArray() to me somehow implies that
> getSomeArray() may return a bool(false) or something like that. On the
> other hand empty(getSomeArray()) seems naturally fit for checking for
> empty arrays.
>
> Another reason is that currently you get a very obscure error message
> if you try to use empty() on a function return value: "Can't use
> function return value in write context". Aha. Where did I try to write
> to the return value?!
>
> So, what do you think?
>
>
I think this is a useful simplification of the language, removing an
unnecessary exception. Would it also make sense to make empty() into a
library function instead of a language construct? That would not result in
any BC break as far as I can see, but would allow some things that are
currently impossible (e.g., a method called "empty") and further simplify
the language.


> Nikita
>
> PS: The patch is trivial: https://gist.github.com/2355274

---

## #59684 — Kris Craig — 2012-04-10T23:15:18+00:00

URL: https://externals.io/message/59681#59684 · In reply to: #59682

On Tue, Apr 10, 2012 at 4:12 PM, Jelle Zijlstra <jelle.zijlstra@gmail.com>wrote:

> 2012/4/10 Nikita Popov <nikita.ppv@googlemail.com>
>
> > […]
> I think this is a useful simplification of the language, removing an
> unnecessary exception. Would it also make sense to make empty() into a
> library function instead of a language construct? That would not result in
> any BC break as far as I can see, but would allow some things that are
> currently impossible (e.g., a method called "empty") and further simplify
> the language.
>
>
> > […]
>

+1 on this.  Could you draft this into an RFC for us?

--Kris

---

## #59685 — johannes@schlueters.de — 2012-04-10T23:31:40+00:00

URL: https://externals.io/message/59681#59685 · In reply to: #59682

> I think this is a useful simplification of the language, removing an
> unnecessary exception. Would it also make sense to make empty() into a
> library function instead of a language construct? That would not
> result in
> any BC break as far as I can see, but would allow some things that are
> currently impossible (e.g., a method called "empty") and further
> simplify
> the language.

It would, as an empty function would spit notices if the variable
doesn't exist (or would have to use references, which would create the
variable  if it didn't exist already) and therefore destroy the primary
use of that construct ... oh and such an empty won't be different from a
simple "if" or bool cast.

johannes

---

## #59686 — Jelle Zijlstra — 2012-04-10T23:37:49+00:00

URL: https://externals.io/message/59681#59686 · In reply to: #59685

2012/4/10 Johannes Schlüter <johannes@schlueters.de>

> 
> > […]
>
> It would, as an empty function would spit notices if the variable
> doesn't exist (or would have to use references, which would create the
> variable  if it didn't exist already) and therefore destroy the primary
> use of that construct ... oh and such an empty won't be different from a
> simple "if" or bool cast.
>
> johannes
>
> You are quite right; I'm sorry for forgetting about that.

---

## #59687 — Stas Malyshev — 2012-04-10T23:51:06+00:00

URL: https://externals.io/message/59681#59687 · In reply to: #59681

Hi!

> Currently the empty() language construct only works on variables. You
> can write if (empty($array)) but not empty if (empty(getSomeArray()).
> 
> The original reason for this restriction probably is that - in a way -
> it "doesn't make sense" to pass anything but a variable to empty() as
> you could just use the ! operator in this case. if
> (empty(getSomeArray())) is logically equivalent to if
> (!getSomeArray()).

Don't see any problem with that, looks good. Please add some tests
(including function calls and some expressions) and make a pull request.
-- 
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

---

## #59690 — Kris Craig — 2012-04-11T00:08:42+00:00

URL: https://externals.io/message/59681#59690 · In reply to: #59687

On Tue, Apr 10, 2012 at 4:51 PM, Stas Malyshev <smalyshev@sugarcrm.com>wrote:

> Hi!
>
> > […]
>
> Don't see any problem with that, looks good. Please add some tests
> (including function calls and some expressions) and make a pull request.
> --
> Stanislav Malyshev, Software Architect
> SugarCRM: http://www.sugarcrm.com/
> (408)454-6900 ext. 227
>
> --
> 
> 
>
>
Err isn't this something that should go through the RFC process first?  I
think it's a good idea and I'll probably vote for it, but as I understand
the RFC process was created specifically for stuff like this.

--Kris

---

## #59693 — Xinchen Hui — 2012-04-11T00:25:26+00:00

URL: https://externals.io/message/59681#59693 · In reply to: #59681

Sent from my iPad

在 2012-4-11，6:54，Nikita Popov <nikita.ppv@googlemail.com> 写道：

> Hey internals!
>
> Currently the empty() language construct only works on variables. You
> can write if (empty($array)) but not empty if (empty(getSomeArray()).
>
> The original reason for this restriction probably is that - in a way -
> it "doesn't make sense" to pass anything but a variable to empty() as
> you could just use the ! operator in this case. if
> (empty(getSomeArray())) is logically equivalent to if
> (!getSomeArray()).
>
> I'd like to propose to change empty() to accept arbitrary expressions.
>
> The reason is simple: Even though it is possible to write if
> (!getSomeArray()) with the same effect, if (empty(getSomeArray()))
> reads much nicer. !getSomeArray() to me somehow implies that
> getSomeArray() may return a bool(false) or something like that. On the
> other hand empty(getSomeArray()) seems naturally fit for checking for
> empty arrays.
+1 for this, but what about is set? They shou be consistent, :)

Thanks
>
> Another reason is that currently you get a very obscure error message
> if you try to use empty() on a function return value: "Can't use
> function return value in write context". Aha. Where did I try to write
> to the return value?!
>
> So, what do you think?
>
> Nikita
>
> PS: The patch is trivial: https://gist.github.com/2355274

---

## #59695 — Stas Malyshev — 2012-04-11T00:46:58+00:00

URL: https://externals.io/message/59681#59695 · In reply to: #59690

Hi!

> Err isn't this something that should go through the RFC process first? 
> I think it's a good idea and I'll probably vote for it, but as I
> understand the RFC process was created specifically for stuff like this.

One doesn't preclude the other. Pull is code, RFC is discussion, they
can go in parallel.
-- 
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

---

## #59697 — Kris Craig — 2012-04-11T01:27:59+00:00

URL: https://externals.io/message/59681#59697 · In reply to: #59695

On Tue, Apr 10, 2012 at 5:46 PM, Stas Malyshev <smalyshev@sugarcrm.com>wrote:

> Hi!
>
> > […]
>
> One doesn't preclude the other. Pull is code, RFC is discussion, they
> can go in parallel.
> --
> Stanislav Malyshev, Software Architect
> SugarCRM: http://www.sugarcrm.com/
> (408)454-6900 ext. 227
>

Well, technically it's discussion *and* vote.  I know we've been wanting to
get out of the habit of "push first, ask later," which is precisely what
RFC helps us avoid.  Personally, I think any commits for a non-minor change
(i.e. a new feature) should be branched and left unmerged until it passes
through the RFC voting process.  I'm a big fan of consistency over ad hoc
processes.  ;)

--Kris

---

## #59705 — Stas Malyshev — 2012-04-11T05:12:12+00:00

URL: https://externals.io/message/59681#59705 · In reply to: #59697

Hi!

> Well, technically it's discussion /and/ vote.  I know we've been wanting
> to get out of the habit of "push first, ask later," which is precisely
> what RFC helps us avoid.  Personally, I think any commits for a

Nobody's pushing anything. We're talking about implementing it in a
fork, it's completely different thing.
-- 
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

---

## #59710 — Kris Craig — 2012-04-11T05:26:52+00:00

URL: https://externals.io/message/59681#59710 · In reply to: #59705

On Tue, Apr 10, 2012 at 10:12 PM, Stas Malyshev <smalyshev@sugarcrm.com>wrote:

> Hi!
>
> > […]
>
> Nobody's pushing anything. We're talking about implementing it in a
> fork, it's completely different thing.
> --
> Stanislav Malyshev, Software Architect
> SugarCRM: http://www.sugarcrm.com/
> (408)454-6900 ext. 227
>

I must've missed that part.  Who was it that said this would be a separate
forked project?  If so, then yeah obviously it's not up to us one way or
another.  And if he's just committing changes locally and/or pushing to an
unmerged branch, then there's no harm because it's not actually touching
the trunk.  What I'm saying is that, before such changes are merged into
the actual PHP 5.4 branch, the idea needs to be voted on through the RFC
process.

Besides, it's a better idea to wait anyway because the simple act of
drafting the RFC helps the author to clarify exactly what s/he wants to do
before jumping into the code.  Furthermore, subsequent input from users may
change the direction, forcing the author to rewrite code, which wastes
time.  And if the proposal is rejected, that person would've written all
that code for nothing.

So either way you look at it, it seems to me at least that drafting the RFC
is the logical first step.

--Kris

---

## #59711 — Pierre Joye — 2012-04-11T05:31:07+00:00

URL: https://externals.io/message/59681#59711 · In reply to: #59710

hi Kris,



> I must've missed that part.  Who was it that said this would be a separate
> forked project?  If so, then yeah obviously it's not up to us one way or
> another.  And if he's just committing changes locally and/or pushing to an
> unmerged branch, then there's no harm because it's not actually touching
> the trunk.  What I'm saying is that, before such changes are merged into
> the actual PHP 5.4 branch, the idea needs to be voted on through the RFC
> process.

All that was asked here is to provide a pull request and a RFC so we
can evaluate this change. Nobody ever mentioned that this change will
be merged into any of our stable branches. Everything's fine and is
done as it should be.

Cheers,
-- 
Pierre

@pierrejoye | http://blog.thepimp.net | http://www.libgd.org

---

## #59713 — Kris Craig — 2012-04-11T05:37:58+00:00

URL: https://externals.io/message/59681#59713 · In reply to: #59711

> hi Kris,
>
> 
>
> > […]
> separate
> > […]
> an
> > […]
>
> All that was asked here is to provide a pull request and a RFC so we
> can evaluate this change. Nobody ever mentioned that this change will
> be merged into any of our stable branches. Everything's fine and is
> done as it should be.
>
> Cheers,
> --
> Pierre
>
> @pierrejoye | http://blog.thepimp.net | http://www.libgd.org
>

Alrighty.  So long as we're not merging any new features or behavioral
changes into the stable branches without an RFC, I'm happy.  =)

--Kris

---

## #59808 — johannes@schlueters.de — 2012-04-12T23:05:31+00:00

URL: https://externals.io/message/59681#59808 · In reply to: #59681

> 
> Currently the empty() language construct only works on variables. You
> can write if (empty($array)) but not empty if (empty(getSomeArray()).

I've mentioned this thought off-list already but let's discuss it
officially:

A fear I have is that this makes empty more looking like a function,
while not being one. Right now one notices quite quickly that it is
something else. Things like $check = $condition ? "empty" : "isset";
$check($bar); trigger an even more confusing error (Call to undefined
function)

I'm not sure whether that's a strong argument, but I guess it's good
enough to be noted :-)

johannes

---

## #59866 — Pal Konyves — 2012-04-13T09:37:00+00:00

URL: https://externals.io/message/59681#59866

> Hi!
>
> "The original reason for this restriction probably is that - in a way -
> it "doesn't make sense" to pass anything but a variable to empty()"
>
> I don't see the point of empty( function() ).
>
> You tipically use empty on values that holds information you want to use
> later in the program flow (a string, an integer). That means you'd better
> extract it to a variable because you want to avoid calling twice a function
> that provides this value.
>
> In my opinion, in other cases a 'isThatStuffTrueOrFalse()' function should
> be created to provide the same information as empty( returnThatStuff() ).
> They both are yes-no questions, but the preceding one is a better
> indication what the program does.
>
> Pal
>
>
> 2012/4/13 Johannes Schlüter <johannes@schlueters.de>
>
> > […]

---

## #59879 — Nikita Popov — 2012-04-13T13:00:34+00:00

URL: https://externals.io/message/59681#59879 · In reply to: #59866

> I don't see the point of empty( function() ).
>
> You tipically use empty on values that holds information you want to use
> later in the program flow (a string, an integer). That means you'd better
> extract it to a variable because you want to avoid calling twice a function
> that provides this value.
You don't always need the value.

Browsing around Google it seems that one of the most common source of
the function call in write context error is people trying to do
if(empty(trim($xyz)). You don't necessarily need the result of
trim($xyz), so it's reasonable not to save it into a temporary
variable.

Another example for example would be a function like this:

public function isValid() {
    if (...) { $this->addError('xyz'); }
    if (...) { $this->addError('abc'); }
    if (...) { $this->addError('foo'); }
    if (...) { $this->addError('bar'); }

    return empty($this->getErrors());
}

Furthermore you don't necessarily have to throw the return value away.
For example I commonly write code like this:

if (null === $result = $this->foo()) {
    throw new Exception(...);
}
$result->doSomething();

You can do something similar with empty():

if (empty($values = $this->getValues()) {
    return;
}
$this->doSomethingWith($values);

I know, not everyone likes that kind of coding style, but I think it
has it's uses.

Nikita

---

## #59880 — Etienne Kneuss — 2012-04-13T13:37:38+00:00

URL: https://externals.io/message/59681#59880 · In reply to: #59879

Hi,


> 
> > […]
> You don't always need the value.
>
> Browsing around Google it seems that one of the most common source of
> the function call in write context error is people trying to do
> if(empty(trim($xyz)). You don't necessarily need the result of
> trim($xyz), so it's reasonable not to save it into a temporary
> variable.

well, empty(trim()) actually is a good example for when you don't want
to use empty(). People typically assume empty checks for the empty
string here, and it doesn't.

>
> Another example for example would be a function like this:
>
> public function isValid() {
>    if (...) { $this->addError('xyz'); }
>    if (...) { $this->addError('abc'); }
>    if (...) { $this->addError('foo'); }
>    if (...) { $this->addError('bar'); }
>
>    return empty($this->getErrors());
> }
>
> Furthermore you don't necessarily have to throw the return value away.
> For example I commonly write code like this:
>
> if (null === $result = $this->foo()) {
>    throw new Exception(...);
> }
> $result->doSomething();
>
> You can do something similar with empty():
>
> if (empty($values = $this->getValues()) {
>    return;
> }
> $this->doSomethingWith($values);
>
> I know, not everyone likes that kind of coding style, but I think it
> has it's uses.

I believe the change is good, but only because it removes an annoying
error condition that is hard to figure out for beginners.

Other than that I don't believe it is useful though: people that know
what empty() really does can use "!expr" when expr is not a variable,
which is less confusing, especially for strings.

Best,

>
> Nikita
>
> --
> 
> 
>



-- 
Etienne Kneuss
http://www.colder.ch

---

## #59883 — Pal Konyves — 2012-04-13T14:22:14+00:00

URL: https://externals.io/message/59681#59883 · In reply to: #59880

Well, if you want to use empty in the above mentioned situations, you might
need the change. I personally don't like using empty(). I use it only on
arrays, that's because semantically fits: array is empty.

In other situations I prefer comparing against the according return type
because it improves code readability. Dynamic typing in PHP one of the
reasons of messy code anyways.

I'm gonna try to give you alternatives of design for your examples below:

> Browsing around Google it seems that one of the most common source of
> the function call in write context error is people trying to do
> if(empty(trim($xyz)). You don't necessarily need the result of
> trim($xyz), so it's reasonable not to save it into a temporary
> variable.

if( trim($xyz) === ""); // as I talked about semantics and types above

>
> Another example for example would be a function like this:
>
> public function isValid() {
>    if (...) { $this->addError('xyz'); }
>    if (...) { $this->addError('abc'); }
>    if (...) { $this->addError('foo'); }
>    if (...) { $this->addError('bar'); }
>
>    return empty($this->getErrors());

return $this->getErrorsCount();

> }
>
> Furthermore you don't necessarily have to throw the return value away.
> For example I commonly write code like this:
>
> if (null === $result = $this->foo()) {
>    throw new Exception(...);
> }
> $result->doSomething();

I used to use this kind of formula, but I realised It neither improves
performance nor readability, especially if you want to use $result after
the if statement.

>
> You can do something similar with empty():
>
> if (empty($values = $this->getValues()) {
>    return;
> }
> $this->doSomethingWith($values);

I haven't try this but I assume this code is valid by precedence order. I
might be wrong, but still my above argument exist.

>
> I know, not everyone likes that kind of coding style, but I think it
> has it's uses.


Etienne Kneuss:
" People typically assume empty checks for the empty
string here, and it doesn't." -- why not?


Pal

---

## #59887 — Etienne Kneuss — 2012-04-13T16:12:48+00:00

URL: https://externals.io/message/59681#59887 · In reply to: #59883

> Well, if you want to use empty in the above mentioned situations, you might
> need the change. I personally don't like using empty(). I use it only on
> arrays, that's because semantically fits: array is empty.
>
> In other situations I prefer comparing against the according return type
> because it improves code readability. Dynamic typing in PHP one of the
> reasons of messy code anyways.
>
> I'm gonna try to give you alternatives of design for your examples below:
>
> > […]
>
> if( trim($xyz) === ""); // as I talked about semantics and types above
>
> > […]
>
> return $this->getErrorsCount();
>
> > […]
>
> I used to use this kind of formula, but I realised It neither improves
> performance nor readability, especially if you want to use $result after
> the if statement.
>
> > […]
>
> I haven't try this but I assume this code is valid by precedence order. I
> might be wrong, but still my above argument exist.
>
> > […]
>
>
> Etienne Kneuss:
> " People typically assume empty checks for the empty
> string here, and it doesn't." -- why not?

What I meant is that when people do:

$str = trim($foo);

if (empty($str)) {

}

they typically want to check if the string is empty, i.e. contains 0
characters. They usually forget that empty() will also return true on
the string "0".

>
>
> Pal



-- 
Etienne Kneuss
http://www.colder.ch

---

## #60466 — Richard Lynch — 2012-05-05T15:48:40+00:00

URL: https://externals.io/message/59681#60466 · In reply to: #59681

> Another reason is that currently you get a very obscure error message
> if you try to use empty() on a function return value: "Can't use
> function return value in write context". Aha. Where did I try to write
> to the return value?!

On the line number indicated in the message :-)

More seriously, if the guts of PHP can easily detect when you are not
really write context versus this, just fix the error message to
something more meaningful.

-- 
brain cancer update:
http://richardlynch.blogspot.com/search/label/brain%20tumor
Donate:
https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FS9NLTNEEKWBE
