See www.zabbix.com for the official Zabbix site.

Docs/specs/coding style

From Zabbix.org
Jump to: navigation, search

Contents

General rules


Database rules

Database table and field names use underscores between words. For example, expand_macros. While old table and field names lack underscores, they will not be mass changed, but new tables and fields, and ones that have to be modified for other reasons, should use underscores.

Language specific rules

shell

Shell scripts (like initscripts) and shell commands inside other files should follow these conventions:

SQL

SQL queries Zabbix components create/use must adhere to the following:

Specifically, in database patches:

For example:

Server SQL statements:

 select hostid,host from hosts where hostid in (1,2,3,4,5,6) and status=3;
 update hosts set host='Zabbix server',ip='127.0.0.1',useip=1 where hostid=1014;

C conventions

Standards

Formatting

struct utsname	name;
 
if (-1 == uname(&name))
        return SYSINFO_RET_FAIL;
package = strtok(buf, "\n");
 
while (NULL != package)
{
	...
 
	package = strtok(NULL, "\n");
}
	res = SUCCEED;
clean:
	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(res));
*lastlogsize = (long)buf.st_size;
zabbix_log(LOG_LEVEL_WARNING, "cannot remove shared memory for collector [%s]", strerror(errno));
#define MEM_MAX_SIZE	0x7fffffff
int	calculate_item_nextcheck(zbx_uint64_t interfaceid, zbx_uint64_t itemid, int item_type,
		int delay, const char *flex_intervals, time_t now, int *effective_delay);
PERFCOUNTER	*counterName = NULL;
DWORD		dwSize;
error = zbx_sock_last_error();	/* zabbix_log() resets the error code */
zabbix_log(LOG_LEVEL_CRIT, "failed assumption about pointer size (%lu not in {4, 8})", ZBX_PTR_SIZE);

Comments

/* check whether we need to update items_hk index */
/* The agent expects ALWAYS to have lastlogsize and mtime tags. Removing those would cause older agents to fail. */
/* do not reallocate if not much is freed */
if (size > chunk_size / 4)
	return chunk;
if (next_free)
{
	/* merge with next chunk */
 
	info->used_size -= chunk_size;
	info->used_size += size;
 
	...
}
free_perf_collector();	/* cpu_collector must be freed before perf_collector is freed */
if (FAIL == result)
{
	/* since we have successfully sent data earlier, we assume the other */
	/* side is just too busy processing our data if there is no response */
	ret = NETWORK_ERROR;
}
/******************************************************************************
 *                                                                            *
 * Comments: counter is NULL if it is not in the collector,                   *
 *           do not call it for PERF_COUNTER_ACTIVE counters                  *
 *                                                                            *
 ******************************************************************************/
PDH_STATUS	zbx_PdhAddCounter(const char *function, PERF_COUNTERS *counter, PDH_HQUERY query, ...

Conditional statements

if (SUCCEED == str_in_list("last,prev", function, ','))
if (0x80 == (*text & 0xc0))
if (NULL != message_esc && 0 != message_esc_len)
if ('1' <= *(br - 2) && *(br - 2) <= '9')
is_numeric |= (SUCCEED == _wis_uint(cpe->szCounterName) ? 0x02 : 0);
if (0 == ioctl(s, SIOCGIFFLAGS, ifr) &&
		0 == (ifr->ifr_flags & IFF_LOOPBACK) &&
		0 == ioctl(s, SIOCGIFHWADDR, ifr))
{
	...
}
if (0 == found)
{
	*curr = zbx_strpool_intern(new);
}
else if (0 != strcmp(*curr, new))
{
	zbx_strpool_release(*curr);
	*curr = zbx_strpool_intern(new);
}
else
	return FAIL;
switch (dcheck->type)
{
	case SVC_TELNET:
		service = "telnet";
		break;
	case SVC_ICMPPING:
		break;
	default:
		return FAIL;
}

Macros

#define ZBX_PROCESS_SERVER	0x01
#ifdef HAVE_LDAP
#ifdef HAVE_LIBCURL
#	include <curl/curl.h>
#	if !defined(HAVE_FUNCTION_CURL_EASY_ESCAPE)
#		define curl_easy_escape(handle, string, length) curl_escape(string, length)
#	endif
#endif
#ifndef _WINDOWS
int	get_cpustat(AGENT_RESULT *result, int cpu_num, int state, int mode);
#endif
#ifdef _WINDOWS
#	include "perfmon.h"
#	include "perfstat.h"
#endif
#ifdef _WINDOWS
				if (WSAEAFNOSUPPORT == zbx_sock_last_error())
#else
				if (EAFNOSUPPORT == zbx_sock_last_error())
#endif
#ifdef _WINDOWS
 
...
 
#else	/* not _WINDOWS */
 
...
 
#endif

Compiler-specific issues

This section describes why we do not use full features of our programming language and current best practices because of incompatibility with older compilers and software.

zabbix_log(LOG_LEVEL_DEBUG, "In %s() datalen:" ZBX_FS_SIZE_T, __function_name, (zbx_fs_size_t)j->buffer_size);
Older versions of glibc do not support z modifier:
zabbix_log(LOG_LEVEL_DEBUG, "In %s() datalen:%zu", __function_name, j->buffer_size);
#ifdef HAVE_LIBCURL
#	include <curl/curl.h>
#	if !defined(HAVE_FUNCTION_CURL_EASY_ESCAPE)
#		define curl_easy_escape(handle, string, length) curl_escape(string, length)
#	endif
#endif
Some compilers do not recognize the following code as valid:
#ifdef HAVE_LIBCURL
	#include <curl/curl.h>
	#if !defined(HAVE_FUNCTION_CURL_EASY_ESCAPE)
		#define curl_easy_escape(handle, string, length) curl_escape(string, length)
	#endif
#endif
#ifdef _WINDOWS
			if (PF_INET6 == current_ai->ai_family &&
				ZBX_TCP_ERROR == setsockopt(s->sockets[s->num_socks], IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on)))
#else
			if (PF_INET6 == current_ai->ai_family &&
				ZBX_TCP_ERROR == setsockopt(s->sockets[s->num_socks], SOL_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on)))
#endif
Some compilers do not recognize the following code as valid:
			if (PF_INET6 == current_ai->ai_family &&
#ifdef _WINDOWS
				ZBX_TCP_ERROR == setsockopt(s->sockets[s->num_socks], IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on)))
#else
				ZBX_TCP_ERROR == setsockopt(s->sockets[s->num_socks], SOL_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on)))
#endif
char	*p_dst = NULL;
Some compilers have trouble compiling more complicated expressions like the following:
size_t	src_size = strlen(src);
int	feeds = src_size / maxline - (0 != src_size % maxline ? 0 : 1);

PHP conventions

public function do(array arrayParameter, classNameOrInterface classParameter) {}
if ($var === null) {}

Input field limits

All input fields in the frontend are limited according to what the receiving database field length limit is. API does input length validation the same way.

For example :

Naming conventions

line, audioSystem
MAX_ITERATIONS, COLOR_RED
getName(), computeTotalWidth()
exportHtmlSource(); // NOT: exportHTMLSource();
openDvdPlayer();    // NOT: openDVDPlayer();
class Person {
  private _name;
  ...
}

Class naming

All class names must be in UpperCamelCase. If class extends another class, child class name should be prefixed to parent class name. Example:

class Writer {}
class XmlWriter extends Writer {}
class FastXmlWriter extends XmlWriter {}

Class files naming

Files that contain class should be named as class name with ".php" extension. Example:

 class Writer {} -> Writer.php
 class XmlWriter {} -> XmlWriter.php

Formatting

In PHP files only one opening "<?php" tag must exists at the first line of file. Closing "?>" should be omitted.
If a concatenation with . (a dot) spans multiple lines, the dot is at the end of the previous line (not in the beginning of the next one).

Blank spaces

Example

<?php
 
class Example {
 
	public function ifExample($a, $b) {
		if (convert($a) > $b) {
			echo "a is bigger than b";
		}
		elseif ($a == $b) {
			echo $a." is equal to ".$b[0];
		}
		else {
			echo $this->property;
		}
		$result = ($a < $b) ? $a : $b;
	}
 
	public function forExample() {
		for ($i = 1; $i <= 10; $i++) {
			echo 'Item: ';
			echo $i;
		}
	}
 
	public function foreachEample() {
		$arr = array(1, 2, 3, 4, "b" => 5, "a" => 6);
		foreach ($arr as &$value) {
			$value = (int) $value * 2;
		}
	}
 
	public function whileExample() {
		$i = 1;
		while ($i <= 10) {
			echo $i++;
		}
	}
 
	public function doWhileExample($i) {
		do {
			echo $i--;
		} while ($i > 0);
	}
 
	public function switchExample($i) {
		switch ($i) {
			case 0:
				echo "i equals 0";
			        break;
 
			case 1:
				echo "i equals 1";
				break;
 
			default:
				throw new Exception('Wrong argument');
				break;
		}
	}
 
	public function tryExample() {
		try {
			echo inverse(5)."\n";
		}
		catch (Exception $e) {
			echo 'Caught exception: '.$e->getMessage()."\n";
		}
	}
}
 
?>

Blank lines

PHPDoc

All functions, methods and properties should have a PHPDoc comment with a brief description of it's purpose and interface. Tag descriptions should be aligned using spaces and tags belonging to one group should be separated by a single line to improve readability.

Example

<?php
 
/**
 * Performs a cool magic trick.
 * 
 * @throws Exception if something goes wrong.
 * 
 * @param FairyDust $fairyDust   The FairyDust object to use in the trick
 * @param array     $magicStones An array of magic stones
 * 
 * @return mixed
 */
function performMagic(FairyDust $fairyDust, array $magicStones) { }

Line length

Maximum line length is 120 characters.

Statement formatting

Statement arguments should not be included in parenthesis. See also PEAR standard.

Example:

require_once dirname(__FILE__).'/include/hosts.inc.php';

Compare with null

For comparison with null "===" operator is used, not is_null() function.

Multiline function parameters and array elements

For function parameters and arrays definitions, there is no trailing comma after the last element both for definitions on single and multiple lines. If a function parameter or array element definition spans multiple lines, closing parenthesis should be on a separate line.

Example:

$data = array(
    'username' => $username,
    'password' => $password,
    'email' => $email
);

Function parameters

Formatting

If preprocessing is not required for function parameters, it is passed directly to function without creation of separate variable.

Examples:

DBselect('SELECT i.itemid FROM items');
 
API::Item->get(array(
    'itemids' => array(123),
    'preservekeys' => true,
    'editable' => true
));
Modifying parameters

If the function receives a parameter and modifies it, it should be returned, not passed by reference. This should make the code easier to understand and prevent situations, when a function modifies the array unexpectedly.

Examples:

// this is correct
function modifyValues(array $values) {
    // do the magic
 
    // return the modified values
    return $values;
}
 
// this is wrong!
function modifyValues(array &$values) {
    // do the magic
}

File includes

For file include require_once is used. require_once raises a fatal error if the file is not found. All of the include paths should be relative to the directory of the file, that includes the script.

Example:

// correct
require_once dirname(__FILE__).'/include/hosts.inc.php';
 
// wrong
require_once 'include/hosts.inc.php';

Directory hierarchy

All classes should be placed under classes directory. If there is bunch of classes that are related to one functionality, they should be placed in a sub-directory. Example:

 classes/export/Export.php
 
 classes/export/writers/Writer.php
 classes/export/writers/XmlWriter.php
 classes/export/writers/JsonWriter.php
 
 classes/export/exportelements/ExportElement.php
 classes/export/exportelements/HostExportElement.php
 classes/export/exportelements/ItemExportElement.php

HTML encoding and JavaScript escaping

Example:

// note, that only the GET parameter should be encoded, not the whole string
$span = new CSpan('Hello, '.CHtml::encode($_GET['name']));
echo $span;

Plain HTML example:

<span>Hello, <?php echo CHtml::encode($_GET['name']) ?></span>

Example:

console.log(<?php echo CJs::encodeJson($_GET['name']) ?>);
console.log(<?php echo CJs::encodeJson(array('name' => $_GET['name'], 'key' => $_GET['item'])) ?>);
 
// if the value will be used in HTML code, it should additionally be HTML encoded
jQuery('#name').html(<?php echo CJs::encodeJson(CHtml::encode($_GET['name'])) ?>);

Example:

<a href="#" id="item" data-params="<?php echo CHtml::serialize(array('name' => $_GET['name'], 'key' => $_GET['item'])) ?>">My Item</a>
// the data() method will automatically handle JSON decoding and return an object
jQuery('#item').data('params');

JavaScript conventions

Naming conventions

Blank spaces

DOM traversing

DOM traversing should be done in way, that avoids being limited to a specific DOM structure, e.g using $.closest() instead of $.parent(), $.find() instead of $.children() and using class names and IDs in selectors.

<ul id="list">
	<li class="item">
		<span>
			<a href="#" class="remove">Remove item</a>
		</span>
	</li>
</ul>
<script>
	// correct
	jQuery('#list').on('click', '#list .item .remove', function() {
		jQuery(this).closest('.item').remove();
	});
 
	// wrong
	jQuery('#list').on('click', '#list li span a', function() {
		jQuery(this).parent().parent().remove();
	});
</script>

HTML conventions

Naming conventions

Tag usage

CSS conventions

Selectors

<div class="widget">
	<div class="header"></div>
	<div class="body"></div>
</div>
/* correct */
.widget { ... }
.widget .header { ... }
.widget .body a { ... }
 
/* wrong */
.widget { ... }
.header { ... }
.body a { ... }
 
/* also wrong */
.widget { ... }
.widget-header { ... }
.widget-body a { ... }
.button { ... }
a:visited { ... }
/* some special styles for a widget on the trigger monitoring page */
.w.list.mon-trigger .widget .body { ... }
 
/* different .button styles for forms */
.w.edit .button { ... }
/* correct */
.w.list .item .status strong { ... }
 
/* wrong */
.w.list tr.item td.status strong { ... }

Style definition

/* some common input and button styles */
input { ... }
.button { ... }
 
/* input and button styles inside of object configuration forms */
.w.edit input { ... }
.w.edit .button { ... }
 
/* specific styles for the item configuration form */
.w.edit.cfg-item input { ... }
.w.edit.cfg-item .button { ... }
Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox