Jump to content
Gadgetto

[SOLVED] A question for PHP pros (variable as instanceof argument)

Recommended Posts

Could somebody please tell me why this works ...

$templates = $this->wire('templates');
$messageTemplates = array();
$className = 'FieldtypeMessageMeta';

foreach ($templates as $t) {
    foreach ($t->fields as $f) {
        if ($f->type instanceof $className) {
            $messageTemplates[] = $t->name;
            break;
        }
    }
}
// $messageTemplates array is populated correctly!

... and this doesn't work:

$templates = $this->wire('templates');
$messageTemplates = array();
$className = self::FIELDTYPE_GROUPMAILER_MESSAGE_META; // is set to 'FieldtypeMessageMeta'

foreach ($templates as $t) {
    foreach ($t->fields as $f) {
        if ($f->type instanceof $className) {
            $messageTemplates[] = $t->name;
            break;
        }
    }
}
// $messageTemplates array is empty!

 

Share this post


Link to post
Share on other sites

The self::FIELDTYPE_GROUPMAILER_MESSAGE_META is suspicious, where do you have this code, what class is it in and in what namespace?

I put this in ready.php with and it works fine - note that I used \ProcessWire\FieldtypeEmail:

<?php namespace ProcessWire;

class G {

    private const CLASS_NAME = '\ProcessWire\FieldtypeEmail';

    public function __construct(){
        $templates = \ProcessWire\wire('templates');
        $messageTeplates = array();
        // both of these two below work fine
        $className = '\ProcessWire\FieldtypeEmail';
        // $className = self::CLASS_NAME;

        foreach ($templates as $t) {
            foreach ($t->fields as $f) {
                if ($f->type instanceof $className) {
                    $messageTeplates[] = $t->name;
                    break;
                }
            }
        }

        echo count($messageTeplates);
    }
}

new G();
exit;

Btw you have a typo in $messageTeplates".

Share this post


Link to post
Share on other sites
46 minutes ago, tpr said:

private const CLASS_NAME = '\ProcessWire\FieldtypeEmail';

Isn't this (and similar) superfluous? You are already in the ProcessWire namespace.

Share this post


Link to post
Share on other sites

Apparently "instanceof" doesn't allow constants, strings, or expressions, while is_a() happily accepts all of those. This is news to me, and I'm not entirely sure of the behind the scenes logic, but it probably has something to do with instanceof being a language construct (those sometimes behave a little bit unexpectedly) – or it might simply be a performance optimization. After all instanceof is much better in terms of performance than is_a().

Use variables or literal class names instead – or if you really have to, use the workaround provided by @tpr above, i.e. store the constant value to a variable before use 🙂

  • Like 3

Share this post


Link to post
Share on other sites
1 hour ago, kongondo said:

Isn't this (and similar) superfluous? You are already in the ProcessWire namespace.

Apparently not, my snippet fails when I exclude ProcessWire from it.

1 hour ago, teppo said:

Apparently "instanceof" doesn't allow constants, strings, or expressions

Are you referring to the #5 example here? To my understanding it's the "variable being tested", and not the class name (after the "instanceof"):

http://php.net/manual/en/language.operators.type.php

Edit: I see, when using the constant with the instanceof directly it generates an error.

1 hour ago, teppo said:

use the workaround provided by @tpr above, i.e. store the constant value to a variable before use

He is already doing that 🙂

@Gadgetto Could you post the whole file? Probably we could find what's happening.

 

  • Like 1

Share this post


Link to post
Share on other sites

Just had a look at what PhpStorm offered as abbreviation, and it worked:

private const CLASS_NAME = FieldtypeEmail::class;

// or 
$className = FieldtypeEmail::class;

(it would add a "use" statement if necessary but in this case it didn't as the namespace was already ProcessWire)

Share this post


Link to post
Share on other sites
47 minutes ago, tpr said:

Apparently not, my snippet fails when I exclude ProcessWire from it.

Interesting - it works like this here:

image.thumb.png.aeb4fb05b5ebd9b4313d31f8603ac597.png

Share this post


Link to post
Share on other sites

Same here, but without "\ProcessWire\" the output is 0:

$className = '\FieldtypeEmail';
// or
$className = 'FieldtypeEmail';

 

  • Like 2

Share this post


Link to post
Share on other sites

Sorry @tpr - I actually even left the \ProcessWire\ in the version I posted above - d'oh.

I did try without and wasn't getting an undefined wire error so assumed it was ok.

Share this post


Link to post
Share on other sites
3 hours ago, tpr said:

The self::FIELDTYPE_GROUPMAILER_MESSAGE_META is suspicious, where do you have this code, what class is it in and in what namespace?

This is correctly defined in class body and the debugger confirms it holds the correct string "FieldtypeMessageMeta"

3 hours ago, tpr said:

I put this in ready.php with and it works fine - note that I used \ProcessWire\FieldtypeEmail

OK - this is strange: changing the const definition to

 const FIELDTYPE_GROUPMAILER_MESSAGE_META = '\Processwire\FieldtypeMessageMeta';

... it works as expected! Why is this?

My class file is already namespaced correctly!

 

Share this post


Link to post
Share on other sites
1 minute ago, Gadgetto said:

it works as expected! Why is this?

A PHP oddity, I'm guessing 😁.

Share this post


Link to post
Share on other sites

Hey, just found out its super easy to copy/paste color-coded code from VSCode! 🙂

 

Share this post


Link to post
Share on other sites
1 minute ago, kongondo said:

A PHP oddity, I'm guessing 😁.

The question is: should I use this and risk a future problem with newer PHP versions?

Share this post


Link to post
Share on other sites
5 minutes ago, Gadgetto said:

My class file is already namespaced correctly!

I think it's OK. PHP shouldn't assume that the instance you are checking is in the current namespace, so you should clearly state which one to check against.

Share this post


Link to post
Share on other sites

I know you need to check a constant or variable, but if you enter things directly, you don't need the namespace. I guess it's to do with quoting FieldtypeEmail when assigning to a variable or const that causes the problem.

image.png.27ecbb70fcccaafcc3b3a68142319ed2.png

  • Like 1

Share this post


Link to post
Share on other sites

BTW - this works perfectly without \Processwire  if I use the class name directly:

if ($f->type instanceof FieldtypeMessageMeta) {
Edited by Gadgetto
@adrian: you got me by a few seconds ... :)

Share this post


Link to post
Share on other sites
5 minutes ago, adrian said:

I know you need to check a constant or variable, but if you enter things directly, you don't need the namespace.

Yes. This is how I've been doing it in my modules. Typing \ProcessWire\...every time is a pain I want to avoid 😁.

Share this post


Link to post
Share on other sites
16 minutes ago, adrian said:

I know you need to check a constant or variable, but if you enter things directly, you don't need the namespace. I guess it's to do with quoting FieldtypeEmail when assigning to a variable or const that causes the problem.

I use the class name many times across this class and in derivates - so using the literal class name directly would be a pain if something changes...

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...