Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimization: Don't instantiate Post objects we know we're not going to use #2345

Open
acobster opened this issue Oct 16, 2020 · 3 comments
Open

Comments

@acobster
Copy link
Collaborator

acobster commented Oct 16, 2020

Is your feature request related to a problem? Please describe.

#2333 introduced the new Image API: Timber::get_image() and Timber::get_attachment(). In the PR for that, we concluded that the least surprising API is one that only returns instances of the respective classes (Image and Attachment) from those methods. This raises a minor performance concern: we are potentially instantiating other kinds of Post object when we already have enough information to know we are going to throw those objects away.

Describe the solution you’d like

We can speed up the "unhappy path" a bit if we tell PostFactory what kind of objects we're looking for. One way this might work is with an extra only option passed to ::get_post(), which is forwarded to PostFactory by calling a special method:

$factory = (new PostFactory())->only($options['only'] ?? []);

PostFactory::build() is where we would honor this:

$class = $this->get_post_class($post);
if (!$this->accept($class)) {
  return false;
}
return $class::build($post);

The only option potentially has some utility beyond this scenario, so we could discuss it as part of the public API.

Describe alternatives you’ve considered

???

Additional context

#2342

@gchtr
Copy link
Member

gchtr commented Oct 18, 2020

Could the solution for this be related to this remaining task for 2.x, (also see #2293 (comment))?

Determine what happens when a timber/*/classmap filter callback returns something other than a CoreInterface. (Probably should throw an exception rather than just letting it TypeError.) - also #2293

Apart from doing the checks for Image and Attachment in an accept() method, could we also add a check for CoreInterface? I feel like this falls into the same category.

I think we need to be careful to not replicate the very option we eliminated with Class Maps. If we pass in an only option in certain functions, would we have to potentionally add it in other places, too?

For example, should we update Post::thumbnail() to use Timber::get_image() as well? I know in this case it could only ever be relevant if someone used the _thumbnail_id meta value to store something else, but there might be other cases that apply.

    /**
	 * get the featured image as a Timber/Image
	 *
	 * @api
	 * @example
	 * ```twig
	 * <img src="{{ post.thumbnail.src }}" />
	 * ```
	 * @return \Timber\Image|null of your thumbnail
	 */
	public function thumbnail() {
		$tid = $this->thumbnail_id();

		if ( $tid ) {
			return $this->factory()->from($tid);
		}
	}

@acobster
Copy link
Collaborator Author

I think we need to be careful to not replicate the very option we eliminated with Class Maps.

That's a valid concern, but accept() wouldn't give you the same control as $PostClass did, i.e. it doesn't control the instantiation itself; it just prevents certain edge cases. We could avoid adding it to top-level Timber options by using Factories directly in ::get_image()/::get_attachment(). Perhaps a helper method is in order to avoid a lot of duplication.

@gchtr
Copy link
Member

gchtr commented Nov 2, 2020

@acobster Sounds good to me!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants