npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

isset-php

v1.0.7

Published

Safe and simple PHP isset() for JavaScript

Downloads

235

Readme

isset-php

Pipeline Status JavaScript Style Guide

Safe and simple implementation of PHP isset() for JavaScript.

Installation

This is a zero dependency library that is safe from both ReferenceError: is not defined and TypeError: cannot read property of undefined exceptions.

npm install --save isset-php

Description

TypeScript function signature:

isset(accessor: Function, ...accessors: Function[]): boolean;

Determine if a variable is considered set, this means if a variable is declared and is different than null or undefined.

If a variable has been unset with the delete keyword, it is no longer considered to be set.

isset() will return false when checking a variable that has been assigned to null or undefined. Also note that a null character ("\0") is not equivalent to the JavaScript null constant.

If multiple parameters are supplied then isset() will return true only if all of the parameters are considered set. Evaluation goes from left to right and stops as soon as an unset variable is encountered.

Parameters

accessor
Accessor function returning the variable to be checked.

accessors
Further accessor functions.

Return Values

Returns true if all accessors return a value that is not null or undefined. false otherwise.

Examples

Example #1 isset() Examples

const isset = require('isset-php')
let val = ''

// This will evaluate to true so the text will be printed.
if (isset(() => val)) {
  console.log('This val is set so I will print.')
}

// Less compact but still viable except when trying to use `this` context
if (isset(function () { return val })) {
  console.log('This val is set so I will also print.')
}

In the next examples we'll use console.log() to output the return value of isset().

let a = 'test'
let b = 'anothertest'

console.log(isset(() => a))            // true
console.log(isset(() => a, () => b))   // true

// This might throw a parsing error: Deleting local variable in strict mode
delete a

console.log(isset(() => a))            // false
console.log(isset(() => a, () => b))   // false

let foo = null

console.log(isset(() => foo))          // false

This also work for elements in objects:

let a = { test: 1, hello: null, pie: { a: 'apple' } }

console.log(isset(() => a.test))       // true
console.log(isset(() => a.foo))        // false
console.log(isset(() => a.hello))      // false

// The key 'hello' equals null so is considered unset. If you want to check for
// null key values then try:
console.log(Object.prototype.hasOwnProperty.call(a, 'hello')) // true

// Checking deeper object values
console.log(isset(() => a.pie.a))      // true
console.log(isset(() => a.pie.b))      // false
console.log(isset(() => a.cake.a.b))   // false

Example #2 isset() on String Offsets

const expectedArrayGotString = 'somestring'

console.log(isset(() => expectedArrayGotString.some_key))
console.log(isset(() => expectedArrayGotString[0]))
console.log(isset(() => expectedArrayGotString['0']))
console.log(isset(() => expectedArrayGotString[0.5]))
console.log(isset(() => expectedArrayGotString['0.5']))
console.log(isset(() => expectedArrayGotString['0 Mostel']))

Output of the above example in PHP 5.4 and above:

false
true
true
true  <-- PHP casts 0.5 to 0 for string offsets and throws a notice
false
false

Output of the above example in JavaScript:

false
true
true
false <-- JS does not cast 0.5 to 0
false
false

This is the only caveat with the JavaScript port as this behaviour is not emulated.


Explanation

Pulled from StackOverflow.

PHP

Note that in PHP you can reference any variable at any depth - even trying to access a non-array as an array will return a simple true or false:

// Referencing an undeclared variable
isset($some); // false

$some = 'hello';

// Declared but has no depth(not an array)
isset($some); // true
isset($some['nested']); // false

$some = ['nested' => 'hello'];

// Declared as an array but not with the depth we're testing for
isset($some['nested']); // true
isset($some['nested']['deeper']); // false

JavaScript

In JavaScript, we don't have that freedom, we'll always get an error if we do the same because JS is immediately attempting to access the value of deeper before we can wrap it in our isset() function so...

// Common pitfall answer(ES6 arrow function)
const isset = (ref) => typeof ref !== 'undefined'

// Same as above
function isset (ref) { return typeof ref !== 'undefined' }

// Referencing an undeclared variable will throw an error, so no luck here
isset(some) // Error: some is not defined

// Defining a simple object with no properties - so we aren't defining
// the property `nested`
let some = {}

// Simple checking if we have a declared variable
isset(some) // true

// Now trying to see if we have a top level property, still valid
isset(some.nested) // false

// But here is where things fall apart: trying to access a deep property
// of a complex object; it will throw an error
isset(some.nested.deeper) // Error: Cannot read property 'deeper' of undefined
//         ^^^^^^ undefined

More failing alternatives:

// Any way we attempt to access the `deeper` property of `nested` will
// throw an error
some.nested.deeper.hasOwnProperty('value') // Error
//   ^^^^^^ undefined

// Similar to the above but safe from objects overriding `hasOwnProperty`
Object.prototype.hasOwnProperty.call(some.nested.deeper, 'value') // Error
//                                        ^^^^^^ undefined

// Same goes for typeof
typeof some.nested.deeper !== 'undefined' // Error
//          ^^^^^^ undefined

And some working alternatives that can get redundant fast:

// Wrap everything in try...catch
try {
  if (isset(some.nested.deeper)) {
    // ...
  }
} catch (e) {}

try {
  if (some.nested.deeper !== undefined && some.nested.deeper !== null) {
    // ...
  }
} catch (e) {}

// Or by chaining all of the isset which can get long
isset(some) && isset(some.nested) && isset(some.nested.deeper) // false
//                        ^^^^^^ returns false so the next isset() is never run