Creative portal «Terra Ad Caelum»
Book Reader
Books overview

 

Quotes

488
Zend Certification Study Guide: Third Edition

Author(s): Davey Shafik, Ben Ramsey

 

Quotation:

Page:        

10 p.

With the release of PHP 5.4, short tags and echo-tags were split, and echo tags are now always enabled.

11 p.

Short tags, script tags and ASP tags are all considered deprecated and their use is strongly discouraged.

14 p.

It’s important to understand that echo is not a function and, as such, it does not have a return value. If you need to output data as part of a more complex expression, you can use print() instead,which, whilst also a language construct, behaves like a function, as it has a return value (which is always 1)

17 p.

PHP doesn’t track overflows, so that the result of a seemingly innocuous operation such as an addition can have catastrophic consequences on the reliability of your application....
(int) (( 0.1 + 0.7 ) * 10 );

18 p.

You should consider using the arbitrary precision functions provided by the BCMath extension (http://php.net/manual/en/book.bc.php) instead of PHP’s built-in data types

21 p.

Casting to an object will result in a new stdClass object.

22 p.

boolval()  cast the given variable to a boolean. Added in PHP5.5

23 p.

There is, however, a special method, is_numeric(), which will return true if passed any variable that is a number-this includes integers, floats, and strings starting with integers or floats.

27 p.

Another option for debugging is debug_zval_dump(). This outputs the internal engine representation of a variable. However, this function is rarely used. The final inspecting option, is var_export(). This allows you to output a syntactically valid string representation of a variable,which if you were to execute it with PHP, would re-create the same variable value.

29 p.

Prior to PHP 5.5, empty() only accepted variables for its argument; from PHP 5.5, it will accept any valid expression

33 p.

Power $a = 2 ** 3; Added in PHP 5.6 Returns the left operand raised to the power of the right.

37 p.

You must, however, be aware of the fact that, even though these operations can approximate a multiplication or a division by a power of two, they are not exactly the same thing—in particular,there are overflow and underflow scenarios that can yield unexpected results.

40 p.

Objects, which are always passed by reference,regardless of whether the & operator is used or no...
by-reference activity is often slower than its by-value counterpart, because PHP uses a clever “deferred-copy” mechanism that actually optimizes by-value assignment

45 p.

@ operator is considered bad practice.
If you must use it, you can install the pecl extension xdebug and enable the xdebug.scream option to stop it hiding the errors during development. The backtick operator makes it possible to execute a shell command and retrieve its output... put of the UNIX ls command to be stored inside $a: $a = `ls -l` ; Don’t confuse the backtick operator with regular quotes (and, conversely, don’t confuse the latter with the former!).

49 p.

With PHP 5.3 the ternary operator has become even shorter! It will return the result of the left-hand expression on true if you omit a true value and remove any white space between the ? and :like so: $foo = $bar ?: $bat;

55 p.

The built-in PHP_EOL constant represents the “end of line” marker for your current operating system.

57 p.

While you can place any code within a namespace, only classes, traits, interfaces, functions, and constants are affected by them

58 p.

To place code in the global scope, you use the anonymous namespace, but you must use curly braces:
namespace {
// Code in the global space
}

59 p.

if (extension_loaded('iconv')) {
return \iconv_strlen...
} elseif (extension_loaded('mbstring')) {
return \mb_strlen..
}

60 p.

For functions and constants, the PHP engine will use global functions or constants if one does not exist inside the namespace—unless you have tried to use the function or constant

62 p.

namespace Ds\String;
$class = Unicode::CLASS; // \Ds\String\Unicode The “constant” name CLASS is case-insensitive

63 p.

Since namespaces were introduced, you have been able create functions and constants within them. However, until PHP 5.6 you could not import those functions and constants, and had to refer to them by either their fully-qualified name or an aliased name.

64 p.

With PHP 5.6 we can import functions and constants and even override built-in PHP functions/constants in the global space.

71 p.

Global introduces an element of confusion into their code, and that “connecting” a function’s scope with the global scope can easily become a source of problems. They prefer, instead, to use the $GLOBALS super global array, which contains all the variables in the global scope

76 p.

Note—and this is very important—that only variables can be passed as by-reference arguments; you cannot pass an expression as a by-reference parameter.

77 p.

Family of functions. PHP provides three built-in functions to handle variable-length argument lists: func_num_args(), func_get_arg() and func_get_args().

79 p.

PHP 5.6 introduced a new feature called variadics. Variadics allow you to explicitly denote a function as accepting a variable length argument list. The syntax for variadics is an argument variable prefixed with three periods: ... $args. The variadic argument must be the last argument in the argument list.

81 p.

n PHP 5.6, the same syntax is used for another new feature known as argument unpacking or “splat....
Argument unpacking works the opposite of the way variadics does,allowing you to unpack an array-like data structure into an argument list when calling a function or method.
$args = [ "World" , "Universe" , "Hello World" ];
echo str_replace ( ... $args ); // Returns "Hello Universe"

85 p.

echo "Citation: {$names[1]}[1987]";
be looking for the variable $mes, which obviously does not exist. In the second example, if the braces were not available, the parser would interpret our input as $names[1][1987], since the square brackets are used for array syntax

87 p.

You cannot interpolate variables when using heredoc to define properties. Nowdoc can be used with no issue.

89 p.

As in most cases in which an alternative function is supported, to test with iconv, use iconv_strlen(); similarly, with mbstring, use mb_strlen() instead.

92 p.

Addition to comparison operators, you can also use the specialized functions strcmp() and strcasecmp() to match strings.These are identical, with the exception that the former is case-sensitive, while the latter is not. In both cases, a result of zero indicates that the two strings passed to the function are equal:

93 p.

A further variant of strcasecmp(), strncasecmp() allows you to only test a given number of characters inside two strings....
You can also perform a comparison between portions of strings by using the substr_compare() function

95 p.

The strstr() function works similarly to strpos() in that it searches the haystack for a needle. The only real difference is that this function returns the portion of the haystack that starts with the needle instead of the latter’s position.

96 p.

You can use the strspn() function to match a string against a “whitelist” mask of allowed characters. This function returns the length of the initial segment of the string that contains any of the characters specified in the mask.

97 p.

Simple Search and Replace Operations Replacing portions of a string with a different substring is another very common task for PHP developers. Simple substitutions are performed using str_replace() -- as well as its case-insensitive variation, str_ireplace.

98 p.

Optionally, you can specify a third parameter, passed by reference, that the function fills, upon return, with the number of substitutions made.

100 p.

To replace a portion of a needle of which you already know the starting and ending point, you can use substr_replace()

104 p.

money_format(), we must specify the formatting rules... national or international rules. The money_format() function is not available on Windows, nor on some variants of UNIX.

110 p.

Parsing Formatted Input The sscanf() family of functions works in a similar way to printf(), except that, instead of formatting output, it allows you to parse formatted input

112 p.

Most notably, Mastering Regular Expressions, by Jeffrey Friedl, published by O’Reilly Media.

114 p.

To make a quantifier ungreedy, simply follow it by a question mark?: /`(.*?)`/

115 p.

u - treats both the pattern and subject as UTF-8 string

118 p.

Named Matches For convenience, we can also name our matches by adding a? or ?'name' inside the parentheticals:

134 p.

As you can see, the equivalence operator == returns true if both arrays have the same number of elements with the same values and keys, regardless of their order. The identity operator ===, on the other hand, returns true only if the array contains the same key/value pairs in the same order.

142 p.

For large arrays, passing by reference reduces memory usage.

148 p.

We are able to convert each of the array’s values to uppercase. One thing to note about array_walk_recursive() is that it will not call the user-defined function on anything but scalar values.

151 p.

SORT_NATURAL Compare all elements as strings, using“natural ordering” like the natsort function. SORT_FLAG_CASE When combined with SORT_STRING or SORT_NATURAL, compare all elements as case-insensitive strings.

152 p.

The natsort() function will, unlike sort(), maintain all the key-value associations in the array. A case-insensitive version of the function, natcasesort() also exists, but there is no reverse-sorting equivalent of rsort().

155 p.

As you can see, usort() has lost all key-value associations and renumbered our array; this can be avoided by using uasort() instead. You can even sort by key (instead of by value) by using uksort().

159 p.

Arrays as Stacks, Queues and Sets Arrays are often used as stack (Last In, First Out, or LIFO) and queue (First In, First Out, or FIFO) structures. PHP simplifies this approach by providing a set of functions that can be used to push and pop (for stacks) and shift and unshift (for queues) elements from an array.

163 p.

Dereferencing Arrays PHP 5.4 introduced the ability to access array members directly when an array is returned by a function: array Result()[ "foo" ];

173 p.

Usually, EGPCS, meaning Environment, Get, Post, Cookie and Built-in variables. Note that $_REQUEST only contains cookie, GET, and POST information.

175 p.

Finally, you can use is_uploaded_file() to determine that a would be hacker hasn’t somehow managed to trick PHP into building a temporary file name that, in reality, points to a different location. Once you verify that the file is a legitimate upload, call move_uploaded_file() to move it to a permanent location. Note that a call to the latter function also checks whether the source file is a valid upload file, so there is no need to call is_uploaded_file() first.

178 p.

ob_start ( "ob_gzhandler" );
Placing this line of code at the top of a page will invoke PHP’s output buffering mechanism, and cause it to transparently compress the script’s output...
zlib.output_compression = on
zlib.output_compression_level = 9

179 p.

Since these settings can be turned on and off without changing your code, this is the best way of implementing compression within your application.

184 p.

Using session.use_trans_sid to embed the session ID in the URL is a security risk. Users could share their session ID by sending the URL to a third-party, who could then hijack their session. Setting session.use_only_cookies will also ensure that only cookie-based sessions are used. You should always use cookie-based session.
...
In the interest of security, it is a good idea to follow your call to session_start() with a call to session_regenerate_id() whenever you change a user’s privileges

186 p.

The addition of the SessionHandlerInterface we can now simply define a class that implements it and pass an instance of that class in as the single argument.

201 p.

The file pointer itself can be moved without reading or writing data by using the fseek() function, which takes three parameters:the file handle, the number of bytes by which the pointer is to be moved, and the position from which the move must take place.This last parameter can contain one of three values: SEEK_SET (start from the beginning of the file), SEEK_CUR (start from the current position), and SEEK_END (start from the end of the file).

202 p.

To find the current position of the pointer, you should useftell().

203 p.

As an example, readfile() will read a file and write it immediately to the script’s standard output. This is useful when you need to include static files, as it offers much better performance:
header ("content-type: video/mpeg");
readfile ("my_home_movie.mpeg");

206 p.

chdir(), which like the UNIX command, changes the current working directory.
Incidentally, you can find out what the current working directory is by calling getcwd()

208 p.

The internal cache maintained within PHP for these functions can be cleared by calling clearstatcache().

210 p.

One aspect of streams that is not always immediately obvious is the fact that they affect pretty much all of PHP’s file access functionality, including require() and include()

211 p.

by setting the allow_url_fopen INI setting to 0 (or off), or you can just disable their use in include and require (and their*_once variants) by setting the allow_url_include INI setting to 0 (or off)

212 p.

If you wish to set a default context for a stream, you can use stream_context_set_default(), which takes the same input as stream_context_create().

214 p.

You can add a filter to a stream by using stream_filter_prepend() and stream_filter_append()

216 p.

phar extension, which allows you to create and distribute entire PHP applications as single file archives.

232 p.

The LIKE operator, which provides a case-insensitive match and allows the use of the % wildcard character to indicate an arbitrary number of characters.

235 p.

Right joins are analogous to left joins, only reversed: instead of returning all results from the “left” side, the right join returns all results from the “right” side, restricting results from the “left” side to matches of the ON clause. Beware, however, that the type of join used will impact the data returned, so be sure to use the correct type of join for the job.

236 p.

They offer atomicity, consistency, isolation, and durability, or ACID.

239 p.

MySQL client library contains a few quirks that cause some irregularities when using the PDO_MYSQL driver, specifically with regard to prepared statements. To resolve these irregularities, it is necessary to set a PDO attribute after connecting to the database. The following line of code will set PDO to use its own native query parser for prepared statements instead of the MySQL client library API:
$dbh->setAttribute( PDO::ATTR_EMULATE_PREPARES , TRUE );
...
a best practice; it is also very useful in debugging. Note that the default error mode for PDO is PDO::ERRMODE_SILENT, which means that it will not emit any warnings or error messages.

242 p.

By default, the fetch mode for a PDOStatement is PDO::FETCH_BOTH,which means that it will return an array containing both associative and numeric indexes.
PDO provides the PDO::exec() method, which executes an SQL statement and returns the number of rows affected.

243 p.

If a database does not support prepared statements, PDO will internally emulate the functionality. If a database driver does support prepared statements, however, PDO will use the native database functionality for prepared statements, improving the performance of your application, since most database engines internally cache prepared statements for reuse.

251 p.

Since mysqli does not throw exceptions, the try/catch blocks are not present in these examples. Instead, after attempting to make a database connection, you’ll note the use of mysqli_connect_error().

252 p.

Using the real_query methods is beneficial, however, since these methods allow you to call stored procedures and work with buffered queries.

258 p.

To disable this functionality and begin a transaction, set the auto-commit mode to FALSE using the autocommit methods. Please note that the autocommit methods will not work with non transactional table types, such as MyISAM or ISAM.

260 p.

The use of mysqlnd is optional; however, it is now the recommended—and default—option, bringing performance and feature gains.
...
more powerful feature additions of mysqlnd is a plugin architecture
...
mysqlnd_ms: A replication and load-balancing plugin that allows you to do simple load balancing and read-write splitting mysqlnd_memcache: Transparently translates SQL into requests for the MySQL InnoDB Memcached Daemon Plugin

262 p.

All string data must be UTF-8 encoded for json_encode() to work properly.

264 p.

JSON_HEX_APOS Convert all apostrophes (') to their hex equivalents (\u0027).
JSON_HEX_QUOT Convert all straight double quotes (") to their hex equivalent (\u0022).

266 p.

In PHP 5.5, a third parameter, depth was added; this limits how many nested data structures will be encoded.
...
With PHP 5.4, a new interface, JsonSerializable, was added that allows you to control what data is encoded when json_encode() is called on your object

268 p.

If you want to force json_decode to return an array, just pass true for the second argument assoc.
Additionally, you can specify depth and options as the third and fourth arguments, respectively. These work the same as for json_encode(), with the exception that the JSON_BIGINT_AS_STRING is the only option supported.

271 p.

Additionally, you can change the date/time by passing relative date/time strings in to DateTime->modify() (e.g., -3 week, or +32 hours16 minutes).

ConstantDescriptionDateTime::ATOM -> Y-m-d\TH:i:sP
DateTime::COOKIE -> l, d-M-Y H:i:s T
DateTime::ISO8601 -> Y-m-d\TH:i:sO

272 p.

DateTime::RSS -> D, d M Y H:i:s O
DateTime::W3C -> Y-m-d\TH:i:sP

273 p.

If we create two DateTime objects with the same date/time in different timezones, they will be equal.

280 p.

XML data model... short, elements contain data, while attributes contain metadata. Some refer to this as the “principle of core content

290 p.

To effectively remove children and attributes, you must export your SimpleXMLElement to DOM

295 p.

In fact, DomXPath is far more powerful than its SimpleXML equivalent.

296 p.

To create newDomElement objects by using the DomDocument::createElement(), DomDocument::createElementNS(), and DomDocument::createTextNode()

301 p.

XML document: attributes, elements, and CDATA. DOM provides a different method for each of these tasks: DomNode::removeAttribute(), DomNode::removeChild(), and DomCharacterData::deleteData().

314 p.

Note that, if the __construct() method is not found, PHP will look for the old PHP 4-style constructor (foo) and call that instead. As of PHP 5.3.3, the old style constructors are not called for namespaced classes

317 p.

__invoke() Called when an object is used as a function(e.g. $object()). Since 5.3
...
__set_start() (Static) Intercept output and re-initalizing via var_export(). Since 5.1
...
__debugInfo() Intercept the output for var_dump()

318 p.

final - The resource is accessible from any scope, but cannot be overridden in descendant classes.
...
The final visibility level only applies to methods and classes. Classes that are declared as final cannot be extended.

322 p.

As of PHP 5.6, you can use contents scalar expressions, discussed in the PHP Basics Chapter, to initialize a property.

324 p.

PHP 5.3 added the ability to use a variable class name for static access.
PHP 5.4 added support for dynamic static method access using the ClassName::$var or ClassName::{expression}() syntax

326 p.

PHP 5.3.0 introduced late static binding (also known as LSB),which will determine the current class at runtime. It has similar semantics to $this and refers to wherever the call happens, not the definition, but with the context of wherever it is defined. This is achieved by using the static:: identifier.

334 p.

By default, SPL uses its own autoloader, called spl_autoload(); this built-in function checks all include paths for filenames that match the name of the class that needs loading in lowercase letters,followed by .inc, .php

335 p.

Note that spl_autoload_register() has a second argument, throw,that, when set to true, will throw an exception when it is unable to register the autoloader.
...
PHP 5.3, spl_autoload_register() now accepts a third argument, prepend, which, when set to true, will prepend the autoloader on the stack.

344 p.

Closures PHP 5.3 added anonymous functions, otherwise known as Closures. Closures allow you to define anonymous functions that can be passed around as callbacks.

347 p.

In PHP 5.4 and later, when a closure is defined within an object scope, this is determined by the object within whose scope it is defined (or in which it is inherited for child classes). This can be changed after the fact by using the bindTo and (static) bind methods of the closure class.

354 p.

In particular, PHP 5.3 added Closures (read more in the Closures and Callbacks chapter), PHP 5.4 added Traits for horizontal reuse, and PHP 5.5 added Generators for simpler iterators and coroutines.

356 p.

While traits do not support inheritance from other traits, you can simply use a trait within another trait

357 p.

In traits that are used in the parent class are inherited identically to any other method in the parent class, and will resolve for parent::method() call

358 p.

class MyClass
{
use Ds\Util\SecureDebugInfo,
My\Framework\DebugHelper { Ds\Util\SecureDebugInfo::__debugInfo insteadof My\Framework\DebugHelper; }
...
}

359 p.

Aliases and Method Visibility: If we wish to still be able to access a conflicted method, we can use an alias, using the as keyword

360 p.

Because traits are like copy-and-paste, the instanceof operator does not work for detecting whether a class utilizes a trait. To check whether a class utilizes a trait, we use the class_uses() function.

368 p.

Active Record pattern. This is used to encapsulate access to a data source so that the act of accessing its components—both for reading and for writing—is, in fact, hidden within the class that implements the pattern, allowing its callers to worry about using the data, as opposed to dealing with the database.

372 p.

The first of these arguments, flags, will allow you to use the actual object properties when iterating (ArrayObject::STD_PROP_LIST), or access the array keys as properties (ArrayObject::ARRAY_AS_PROPS). The second argument, iterator_class, lets you specify a different type of iterator class to be used when iterating over the ArrayObject data.

376 p.

Recursive Iteration allows looping over multi-dimensional tree-like data structures. SimpleXML, for example, uses recursive iteration to allow looping through complex XML document trees.

377 p.

By extending RecursiveIteratorIterator (an example of an OuterIterator), we can define the beginChildren() and endChildren()

380 p.

The abstract FilterIterator class is an OuterIterator that can be used to filter the items returned by an iteration. To use it, extend it with a concrete implementation that implements the accept() method.

382 p.

$dir = new DirectoryIterator ( "./_posts" );
$it = new RegexIterator( $dir , '/^.*\.(md|markdown)$/' );
foreach ($it ...

384 p.

SplStack A stack implementation.
LIFO: Last In, First Out data structure
...
SplQueue A queue implementation,
FIFO: First In, First Out data structure
...
SplPriorityQueue A queue implementation that implements priorities, so that higher priority items will be returned first

385 p.

SplFixedArray A faster array implementation, but with a fixed size, and only allowing integer keys... A generator function is identified by the existence of one or more instances of the yield keyword. When this keyword exists within a function and that function is called, none of the code inside of the function is run. Instead a Generator is returned—the code inside is only run when the Generator is iterated over.

386 p.

$generator = gen();
At this point, although we have called our gen() function, no code has run inside the function. Instead, $generator is now a Generator.

390 p.

A generator is considered closed when one of the following conditions is met: It reaches a return statement. The end of the function is reached. An exception is thrown and not caught inside the generator. All references to the generator are removed (e.g. unset($generator)).

392 p.

Reusing a Generator Unlike regular iterators, or arrays, you cannot reuse a generator. If you call rewind() on a generator after its first yield, it will throw an exception. This means that you cannot iterate using the same generator more than once.... It is also possible to send data into a Generator. This is known as a co-routine

394 p.

it is also possible to send exceptions into the generator

395 p.

The more forethought you give your design, the more likely you are to be able to reuse at least some of it.

398 p.

Error reporting can also be changed dynamically from within a script by calling the error_reporting() function.

400 p.

As of PHP 5.0, set_error_handler() supports a second parameter that allows you to specify the types of errors that a particular handler is responsible for trapping. This parameter takes the same constant values as the error_reporting() function... restore_error_handler() to revert back to the the previous error handler

401 p.

PHP 5.5 you can pass NULL toset_error_handler() in order to return to the default PHP behavior.

407 p.

To restore the previously used exception handler, be it the default of a fatal error or another user defined callback, you can use restore_exception_handler(). New in PHP 5.5: With PHP 5.5 you can pass NULL to set_exception_handler() to return to the default PHP behaviour.... With PHP 5.5, a finally block was added. Code within the finally block will be executed regardless of whether an exception has been thrown or not, making it useful for things like cleanup.

419 p.

All filters are defined by a constant; validation filters are named FILTER_VALIDATION_* and sanitizing filters are named FILTER_SANITIZE_*. Flags, appropriately, are named FILTER_FLAG_*. All filters return the—potentially sanitized—value, or false on failure. This can be tricky when validating booleans using FILTER_VALIDATE_BOOLEAN, as it will also return false when the input is false. To get around this, the flag FILTER_NULL_ON_FAILURE will return null on failure rather than false.

420 p.

If we want to strip tags from all POST values, or maybe a row of data from our database, we can do so very simply:
$clean = filter_input_array (INPUT_POST , FILTER_SANITIZE_STRING)

421 p.

Be aware that FILTER_VALIDATE_URL only allows ASCII domains; internationalized domain names (IDN) must first be converted to puny code using idn_to_ascii(). Additionally,a valid URL does not necessarily mean that it uses the HTTP scheme; you should validate the scheme using parse_url(). PHP 5.4 also introduced an additional argument to both functions...
bcrypt one-way hashing as the best algorithm; it is far superior to MD5, and even SHA-1.

422 p.

Hashing a password is as simple as calling the password_hash() function with the string to hash and the algorithm to use:
$hashed = password_hash("password" , PASSWORD_BCRYPT)

423 p.

Verifying Passwords To verify a password, we use the password_verify() function. This is even simpler than hashing the password.

424 p.

By combining this function with your verification process, you can automatically update your users’ passwords when new algorithms become available.
...
Password is valid
if (password_needs_rehash( $hashed , PASSWORD_DEFAULT )) {
$newhash = password_hash( $_POST [ 'password' ], PASSWORD_DEFAULT );
}

430 p.

A cross-site request forgery (CSRF) is an attack that attempts to cause a victim to send arbitrary HTTP requests, usually to URLs requiring privileged access, using the victim’s existing session to gain access. The HTTP request then causes the victim to execute a particular action based on his or her level of privilege, such as making a purchase or modifying or removing information.

436 p.

You should always use cookie-based sessions. Although there is a directive, session.use_trans_sid, that instructs PHP to append the session identifier to the URLs of your application, doing so exposes the session identifier. Leave this setting at 0 to disable this behavior.

437 p.

session_start (); // If the user login is successful, regenerate the session ID if (authenticate()) { session_regenerate_id ();}

438 p.

Then, on subsequent page loads, check to ensure that the User-Agent has not changed. If it has changed, that is cause for concern,and the user should log in again.

445 p.

There are three popular types of Web services in use today: XML-RPC, SOAP (the successor to XML-RPC), and REST

449 p.

the entire SOAP exchange is to be compressed, and so on. If you are accessing a SOAP service that does not have aWSDL file, it is possible to create a SOAP client in non-WSDL mode by passing a NULL value to the SoapClientconstructor instead of to the location of the WSDL file. Inthis case, you will have to pass the URI to the Web service’sentry point as part of the second parameter... Debugging SoapClient provides special methods that make it possible to debugmessages sent to and received from a SOAP server. Thesemessages can be turned on by setting the trace option to 1 wheninstantiating a SOAP client object

454 p.

array_diff - returns values that exist in a second array, but not in the first.

457 p.

compact - will create an array using the variable

458 p.

extract - create variables for each value of the array in the current scope using the key as the variable name. Only keys whose names are valid variable identifiers are extracted (i.e. non-numeric).

469 p.

phpdbg is similar to the traditional C-debugger, gdb with support for step-through debugging, code disassembly, and remote debugging.